162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2022, Microsoft Corporation. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "mana_ib.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define VALID_MR_FLAGS \ 962306a36Sopenharmony_ci (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ) 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic enum gdma_mr_access_flags 1262306a36Sopenharmony_cimana_ib_verbs_to_gdma_access_flags(int access_flags) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci enum gdma_mr_access_flags flags = GDMA_ACCESS_FLAG_LOCAL_READ; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci if (access_flags & IB_ACCESS_LOCAL_WRITE) 1762306a36Sopenharmony_ci flags |= GDMA_ACCESS_FLAG_LOCAL_WRITE; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci if (access_flags & IB_ACCESS_REMOTE_WRITE) 2062306a36Sopenharmony_ci flags |= GDMA_ACCESS_FLAG_REMOTE_WRITE; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (access_flags & IB_ACCESS_REMOTE_READ) 2362306a36Sopenharmony_ci flags |= GDMA_ACCESS_FLAG_REMOTE_READ; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci return flags; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int mana_ib_gd_create_mr(struct mana_ib_dev *dev, struct mana_ib_mr *mr, 2962306a36Sopenharmony_ci struct gdma_create_mr_params *mr_params) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct gdma_create_mr_response resp = {}; 3262306a36Sopenharmony_ci struct gdma_create_mr_request req = {}; 3362306a36Sopenharmony_ci struct gdma_dev *mdev = dev->gdma_dev; 3462306a36Sopenharmony_ci struct gdma_context *gc; 3562306a36Sopenharmony_ci int err; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci gc = mdev->gdma_context; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_MR, sizeof(req), 4062306a36Sopenharmony_ci sizeof(resp)); 4162306a36Sopenharmony_ci req.pd_handle = mr_params->pd_handle; 4262306a36Sopenharmony_ci req.mr_type = mr_params->mr_type; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci switch (mr_params->mr_type) { 4562306a36Sopenharmony_ci case GDMA_MR_TYPE_GVA: 4662306a36Sopenharmony_ci req.gva.dma_region_handle = mr_params->gva.dma_region_handle; 4762306a36Sopenharmony_ci req.gva.virtual_address = mr_params->gva.virtual_address; 4862306a36Sopenharmony_ci req.gva.access_flags = mr_params->gva.access_flags; 4962306a36Sopenharmony_ci break; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci default: 5262306a36Sopenharmony_ci ibdev_dbg(&dev->ib_dev, 5362306a36Sopenharmony_ci "invalid param (GDMA_MR_TYPE) passed, type %d\n", 5462306a36Sopenharmony_ci req.mr_type); 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (err || resp.hdr.status) { 6162306a36Sopenharmony_ci ibdev_dbg(&dev->ib_dev, "Failed to create mr %d, %u", err, 6262306a36Sopenharmony_ci resp.hdr.status); 6362306a36Sopenharmony_ci if (!err) 6462306a36Sopenharmony_ci err = -EPROTO; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return err; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci mr->ibmr.lkey = resp.lkey; 7062306a36Sopenharmony_ci mr->ibmr.rkey = resp.rkey; 7162306a36Sopenharmony_ci mr->mr_handle = resp.mr_handle; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int mana_ib_gd_destroy_mr(struct mana_ib_dev *dev, u64 mr_handle) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct gdma_destroy_mr_response resp = {}; 7962306a36Sopenharmony_ci struct gdma_destroy_mr_request req = {}; 8062306a36Sopenharmony_ci struct gdma_dev *mdev = dev->gdma_dev; 8162306a36Sopenharmony_ci struct gdma_context *gc; 8262306a36Sopenharmony_ci int err; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci gc = mdev->gdma_context; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_MR, sizeof(req), 8762306a36Sopenharmony_ci sizeof(resp)); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci req.mr_handle = mr_handle; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp); 9262306a36Sopenharmony_ci if (err || resp.hdr.status) { 9362306a36Sopenharmony_ci dev_err(gc->dev, "Failed to destroy MR: %d, 0x%x\n", err, 9462306a36Sopenharmony_ci resp.hdr.status); 9562306a36Sopenharmony_ci if (!err) 9662306a36Sopenharmony_ci err = -EPROTO; 9762306a36Sopenharmony_ci return err; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length, 10462306a36Sopenharmony_ci u64 iova, int access_flags, 10562306a36Sopenharmony_ci struct ib_udata *udata) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct mana_ib_pd *pd = container_of(ibpd, struct mana_ib_pd, ibpd); 10862306a36Sopenharmony_ci struct gdma_create_mr_params mr_params = {}; 10962306a36Sopenharmony_ci struct ib_device *ibdev = ibpd->device; 11062306a36Sopenharmony_ci struct mana_ib_dev *dev; 11162306a36Sopenharmony_ci struct mana_ib_mr *mr; 11262306a36Sopenharmony_ci u64 dma_region_handle; 11362306a36Sopenharmony_ci int err; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci dev = container_of(ibdev, struct mana_ib_dev, ib_dev); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ibdev_dbg(ibdev, 11862306a36Sopenharmony_ci "start 0x%llx, iova 0x%llx length 0x%llx access_flags 0x%x", 11962306a36Sopenharmony_ci start, iova, length, access_flags); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (access_flags & ~VALID_MR_FLAGS) 12262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 12562306a36Sopenharmony_ci if (!mr) 12662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci mr->umem = ib_umem_get(ibdev, start, length, access_flags); 12962306a36Sopenharmony_ci if (IS_ERR(mr->umem)) { 13062306a36Sopenharmony_ci err = PTR_ERR(mr->umem); 13162306a36Sopenharmony_ci ibdev_dbg(ibdev, 13262306a36Sopenharmony_ci "Failed to get umem for register user-mr, %d\n", err); 13362306a36Sopenharmony_ci goto err_free; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci err = mana_ib_gd_create_dma_region(dev, mr->umem, &dma_region_handle); 13762306a36Sopenharmony_ci if (err) { 13862306a36Sopenharmony_ci ibdev_dbg(ibdev, "Failed create dma region for user-mr, %d\n", 13962306a36Sopenharmony_ci err); 14062306a36Sopenharmony_ci goto err_umem; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci ibdev_dbg(ibdev, 14462306a36Sopenharmony_ci "mana_ib_gd_create_dma_region ret %d gdma_region %llx\n", err, 14562306a36Sopenharmony_ci dma_region_handle); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci mr_params.pd_handle = pd->pd_handle; 14862306a36Sopenharmony_ci mr_params.mr_type = GDMA_MR_TYPE_GVA; 14962306a36Sopenharmony_ci mr_params.gva.dma_region_handle = dma_region_handle; 15062306a36Sopenharmony_ci mr_params.gva.virtual_address = iova; 15162306a36Sopenharmony_ci mr_params.gva.access_flags = 15262306a36Sopenharmony_ci mana_ib_verbs_to_gdma_access_flags(access_flags); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci err = mana_ib_gd_create_mr(dev, mr, &mr_params); 15562306a36Sopenharmony_ci if (err) 15662306a36Sopenharmony_ci goto err_dma_region; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* 15962306a36Sopenharmony_ci * There is no need to keep track of dma_region_handle after MR is 16062306a36Sopenharmony_ci * successfully created. The dma_region_handle is tracked in the PF 16162306a36Sopenharmony_ci * as part of the lifecycle of this MR. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return &mr->ibmr; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cierr_dma_region: 16762306a36Sopenharmony_ci mana_gd_destroy_dma_region(dev->gdma_dev->gdma_context, 16862306a36Sopenharmony_ci dma_region_handle); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cierr_umem: 17162306a36Sopenharmony_ci ib_umem_release(mr->umem); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cierr_free: 17462306a36Sopenharmony_ci kfree(mr); 17562306a36Sopenharmony_ci return ERR_PTR(err); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciint mana_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct mana_ib_mr *mr = container_of(ibmr, struct mana_ib_mr, ibmr); 18162306a36Sopenharmony_ci struct ib_device *ibdev = ibmr->device; 18262306a36Sopenharmony_ci struct mana_ib_dev *dev; 18362306a36Sopenharmony_ci int err; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci dev = container_of(ibdev, struct mana_ib_dev, ib_dev); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci err = mana_ib_gd_destroy_mr(dev, mr->mr_handle); 18862306a36Sopenharmony_ci if (err) 18962306a36Sopenharmony_ci return err; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (mr->umem) 19262306a36Sopenharmony_ci ib_umem_release(mr->umem); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci kfree(mr); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 198