// SPDX-License-Identifier: GPL-2.0 // Copyright(c) 2024 Huawei Technologies Co., Ltd #include "roce_mr.h" #include "roce_mr_extension.h" #include "roce_main_extension.h" /* **************************************************************************** Prototype : get_key_from_index Description : get_key_from_index Input : u32 mpt_index Output : None 1.Date : 2015/5/27 Modification : Created function **************************************************************************** */ static u32 get_key_from_index(u32 mpt_index) { /* Algorithm of mr key is obtained by index shift calculation */ return (mpt_index >> MR_KEY_RIGHT_SHIFT_OFS) | (mpt_index << MR_KEY_LEFT_SHIFT_OFS); } /* **************************************************************************** Prototype : convert_ib_access Description : convert ib access to rdma comp access Input : int access_flag Output : None 1.Date : 2015/7/16 Modification : Created function **************************************************************************** */ static u32 convert_ib_access(int access_flag) { u32 u_access_flag = (u32)access_flag; u32 access; access = (u32)((((u_access_flag & IB_ACCESS_REMOTE_ATOMIC) != 0) ? RDMA_IB_ACCESS_REMOTE_ATOMIC : 0) | (((u_access_flag & IB_ACCESS_REMOTE_WRITE) != 0) ? RDMA_IB_ACCESS_REMOTE_WRITE : 0) | (((u_access_flag & IB_ACCESS_REMOTE_READ) != 0) ? RDMA_IB_ACCESS_REMOTE_READ : 0) | (((u_access_flag & IB_ACCESS_LOCAL_WRITE) != 0) ? RDMA_IB_ACCESS_LOCAL_WRITE : 0) | (((u_access_flag & IB_ACCESS_MW_BIND) != 0) ? RDMA_IB_ACCESS_MW_BIND : 0) | (((u_access_flag & IB_ZERO_BASED) != 0) ? RDMA_IB_ACCESS_ZERO_BASED : 0)); return access; } /* **************************************************************************** Prototype : check_ib_access Description : check remote access without local write Input : int access_flag Output : None 1.Date : 2017/11/18 Modification : Created function **************************************************************************** */ static int check_ib_access(int access_flag) { /* * Local write permission is required if remote write or * remote atomic permission is also requested. */ if (((((u32)access_flag) & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE)) != 0) && ((((u32)access_flag) & IB_ACCESS_LOCAL_WRITE) == 0)) return -EINVAL; return 0; } /* **************************************************************************** Prototype : roce3_alloc_tpt Description : alloc mpt and mtt Input : struct roce3_device *rdev struct rdma_mr *mr u32 npages u32 page_shift Output : None 1.Date : 2015/5/8 Modification : Created function **************************************************************************** */ int roce3_alloc_tpt(struct roce3_device *rdev, struct rdma_mr *mr, u32 npages, u32 page_shift) { int ret = 0; ret = hmm_rdma_mpt_alloc(rdev->hwdev, &mr->mpt, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc mpt, ret(%d), func_id(%d)\n", __func__, ret, rdev->glb_func_id); return ret; } mr->enabled = RDMA_MPT_EN_SW; /* * npages = 0 is a legal case, when npages = 0 or npages = 1, * MTT does not need to do address translation */ ret = hmm_rdma_mtt_alloc(rdev->hwdev, npages, page_shift, &mr->mtt, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc mtt, ret(%d), func_id(%d)\n", __func__, ret, rdev->glb_func_id); goto err_alloc_mtt; } return 0; err_alloc_mtt: hmm_rdma_mpt_free(rdev->hwdev, &mr->mpt); mr->enabled = RDMA_MPT_DISABLED; return ret; } /* **************************************************************************** Prototype : roce3_free_tpt Description : free mpt and mtt Input : struct roce3_device *rdev struct rdma_mr *mr Output : None 1.Date : 2015/5/8 Modification : Created function **************************************************************************** */ void roce3_free_tpt(struct roce3_device *rdev, struct rdma_mr *mr) { hmm_rdma_mtt_free(rdev->hwdev, &mr->mtt, SERVICE_T_ROCE); hmm_rdma_mpt_free(rdev->hwdev, &mr->mpt); mr->enabled = RDMA_MPT_DISABLED; } /* **************************************************************************** Prototype : roce3_set_rdma_mr Description : set the member of rdma_mr Input : struct rdma_mr *mr enum rdma_mr_type mr_type u32 pdn u64 iova u64 size u32 access Output : None 1.Date : 2015/5/8 Modification : Created function **************************************************************************** */ void roce3_set_rdma_mr(struct rdma_mr *mr, enum rdma_mr_type mr_type, u32 pdn, u64 iova, u64 size, u32 access) { mr->iova = iova; mr->size = size; mr->pdn = pdn; /* Convert ib permissions to rdma component permissions */ mr->access = convert_ib_access((int)access); /* Convert from mpt index to key */ mr->key = get_key_from_index(mr->mpt.mpt_index); mr->mr_type = mr_type; } /* **************************************************************************** Prototype : roce3_set_rdma_mw Description : set the member of rdma_mw Input : struct rdma_mw *mw u32 pdn enum ib_mw_type type Output : None 1.Date : 2016/6/25 Modification : Created function **************************************************************************** */ static void roce3_set_rdma_mw(struct rdma_mw *mw, u32 pdn, enum ib_mw_type type) { mw->enabled = RDMA_MPT_EN_SW; mw->pdn = pdn; mw->key = get_key_from_index(mw->mpt.mpt_index); if (type == IB_MW_TYPE_1) mw->type = RDMA_MW_TYPE_1; else mw->type = RDMA_MW_TYPE_2; } /* **************************************************************************** Prototype : roce3_get_dma_mr Description : register DMA_MR Input : struct ib_pd *ibpd int access Output : None 1.Date : 2015/4/24 Modification : Created function **************************************************************************** */ struct ib_mr *roce3_get_dma_mr(struct ib_pd *ibpd, int access) { int ret = 0; struct roce3_mr *mr = NULL; struct roce3_pd *pd = NULL; struct roce3_device *rdev = NULL; if ((ibpd == NULL) || (check_ib_access(access) != 0)) { ret = -EINVAL; pr_err("[ROCE, ERR] %s: Invalid Param.p1:%d\n", __func__, access); goto err_out; } pd = to_roce3_pd(ibpd); rdev = to_roce3_dev(ibpd->device); if (roce3_hca_is_present(rdev) == 0) { dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n", __func__, rdev->glb_func_id); ret = -EPERM; goto err_out; } mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (mr == NULL) { ret = -ENOMEM; dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc memory for dma mr, func_id(%d)\n", __func__, rdev->glb_func_id); goto err_out; } mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE; ret = roce3_alloc_tpt(rdev, &mr->rdmamr, 0, 0); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc mpt and mtt, func_id(%d)\n", __func__, rdev->glb_func_id); goto err_alloc_tpt; } /* Set the content in rdma_mr */ roce3_set_rdma_mr(&mr->rdmamr, RDMA_DMA_MR, pd->pdn, 0ULL, ROCE_DMA_MR_SIZE, (u32)access); ret = hmm_rdma_enable_mr_mpt(rdev->hwdev, &(mr->rdmamr), HINIC3_CHANNEL_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to enable mpt of DMA mr, func_id(%d)\n", __func__, rdev->glb_func_id); goto err_enable_mpt; } mr->ibmr.lkey = mr->rdmamr.key; mr->ibmr.rkey = mr->rdmamr.key; return &mr->ibmr; err_enable_mpt: roce3_free_tpt(rdev, &mr->rdmamr); err_alloc_tpt: kfree(mr); err_out: return (struct ib_mr *)ERR_PTR((long)ret); } static int roce3_alloc_priv_pages(struct ib_device *ibdev, struct roce3_mr *rmr, u32 max_pages) { int ret; #ifndef __PC_LINT__ rmr->page_map_size = roundup(max_pages * sizeof(u64), ROCE3_MR_PAGES_ALIGN); #endif rmr->pages = (__be64 *)(void *)(uintptr_t)get_zeroed_page(GFP_KERNEL); if (rmr->pages == NULL) { pr_err("[ROCE] %s: Failed to alloc rmr->pages\n", __func__); ret = -ENOMEM; goto err_out; } rmr->page_map = dma_map_single(ibdev->dev.parent, rmr->pages, rmr->page_map_size, DMA_TO_DEVICE); if (dma_mapping_error(ibdev->dev.parent, rmr->page_map) != 0) { pr_err("[ROCE] %s: Failed to do dma mapping\n", __func__); ret = -ENOMEM; goto err_free_pages; } return 0; err_free_pages: free_page((unsigned long)(uintptr_t)(void *)rmr->pages); err_out: return ret; } static void roce3_free_priv_pages(struct roce3_mr *rmr) { struct ib_device *ib_dev = rmr->ibmr.device; if (rmr->pages) { ib_dev = rmr->ibmr.device; dma_unmap_single(ib_dev->dev.parent, rmr->page_map, rmr->page_map_size, DMA_TO_DEVICE); free_page((unsigned long)(uintptr_t)(void *)rmr->pages); rmr->pages = NULL; } } static int roce3_alloc_mr_param_validate(const struct ib_pd *ibpd, enum ib_mr_type mr_type, u32 max_num_sg) { int ret = 0; if (ibpd == NULL) { ret = -EINVAL; pr_err("[ROCE, ERR] %s: Ibpd is null\n", __func__); goto err_out; } /*lint -e746*/ ret = roce3_check_alloc_mr_type(mr_type); /*lint +e746*/ if (ret != 0) { ret = -EINVAL; pr_err("[ROCE, ERR] %s: mr_type is invalid\n", __func__); goto err_out; } if (max_num_sg >= ROCE_FRMR_MAX_PAGES) { pr_err("[ROCE] %s: Invalid max_num_sg(%d)\n", __func__, max_num_sg); ret = -EINVAL; goto err_out; } return 0; err_out: return ret; } static int roce3_alloc_mr_param_check(struct roce3_device *rdev, struct roce3_mr **mr, u32 max_num_sg) { if (roce3_hca_is_present(rdev) == 0) { dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n", __func__, rdev->glb_func_id); return -ENOMEM; } *mr = kzalloc(sizeof(struct roce3_mr), GFP_KERNEL); if ((*mr) == NULL) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc mr memory, func(%d)\n", __func__, rdev->glb_func_id); return -ENOMEM; } (*mr)->max_pages = max_num_sg; return 0; } /* **************************************************************************** Prototype : roce3_alloc_mr Description : register DMA_MR Input : struct ib_pd *ibpd enum ib_mr_type mr_type u32 max_num_sg Output : None 1.Date : 2015/4/24 Modification : Created function **************************************************************************** */ struct ib_mr *roce3_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, u32 max_num_sg) { int ret = 0; struct roce3_mr *mr = NULL; struct roce3_pd *pd = NULL; struct roce3_device *rdev = NULL; ret = roce3_alloc_mr_param_validate(ibpd, mr_type, max_num_sg); if (ret != 0) goto err_out; pd = to_roce3_pd(ibpd); rdev = to_roce3_dev(ibpd->device); ret = roce3_alloc_mr_param_check(rdev, &mr, max_num_sg); if (ret != 0) goto err_out; mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE; ret = roce3_alloc_tpt(rdev, &mr->rdmamr, max_num_sg, 0); // alloc mptc and mtt if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc tpt, func(%d)\n", __func__, rdev->glb_func_id); goto err_alloc_tpt; } ret = roce3_alloc_priv_pages(ibpd->device, mr, max_num_sg); // alloc memory to store pa if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to alloc memory, func(%u)\n", __func__, rdev->glb_func_id); goto err_alloc_priv_pages; } /*lint -e746*/ roce3_set_rdma_mr(&mr->rdmamr, RDMA_FRMR, pd->pdn, 0ULL, 0, 0); /*lint +e746*/ /* send to chip by cmdq */ ret = hmm_rdma_enable_mr_mpt(rdev->hwdev, &(mr->rdmamr), HINIC3_CHANNEL_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to enable mpt, func(%d)\n", __func__, rdev->glb_func_id); goto err_enale_mpt; } mr->ibmr.lkey = mr->rdmamr.key; mr->ibmr.rkey = mr->rdmamr.key; return &mr->ibmr; err_enale_mpt: roce3_free_priv_pages(mr); err_alloc_priv_pages: roce3_free_tpt(rdev, &mr->rdmamr); err_alloc_tpt: kfree(mr); err_out: return (struct ib_mr *)ERR_PTR((long)ret); } static int roce3_set_page(struct ib_mr *ibmr, u64 addr) { struct roce3_mr *rmr = NULL; if (ibmr == NULL) { pr_err("[ROCE] %s: Ibmr is null\n", __func__); return -EINVAL; } rmr = to_roce3_mr(ibmr); if (ROCE_UNLIKELY(rmr->npages >= rmr->max_pages)) { pr_err("[ROCE] %s: Invalid npages(0x%x), can't set page\n", __func__, rmr->npages); return -ENOMEM; } rmr->pages[rmr->npages] = cpu_to_be64(addr | 0x1); rmr->npages++; return 0; } int roce3_map_kernel_frmr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, unsigned int *sg_offset) { int ret; struct roce3_mr *rmr = NULL; /* sg_offset can be null */ if ((ibmr == NULL) || (sg == NULL)) { pr_err("[ROCE] %s: Ibmr or sg is null\n", __func__); return -EINVAL; } rmr = to_roce3_mr(ibmr); rmr->npages = 0; if (ROCE_UNLIKELY(((u32)sg_nents) >= rmr->max_pages)) { pr_err("[ROCE] %s: Invalid sg_nents(0x%x), ,max(0x%x)\n", __func__, sg_nents, rmr->max_pages); return -EINVAL; } ib_dma_sync_single_for_cpu(ibmr->device, rmr->page_map, rmr->page_map_size, DMA_TO_DEVICE); ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, roce3_set_page); ib_dma_sync_single_for_device(ibmr->device, rmr->page_map, rmr->page_map_size, DMA_TO_DEVICE); return ret; } static int roce3_umem_write_mtt_check(const struct roce3_device *rdev, const struct rdma_mtt *mtt, const struct ib_umem *umem) { if ((rdev == NULL) || (mtt == NULL) || (umem == NULL)) { pr_err("[ROCE, ERR] %s: Rdev or mtt or umem is null\n", __func__); return -EINVAL; } return 0; } static int roce3_umem_write_mtt_update(struct roce3_device *rdev, struct rdma_mtt *mtt, struct ib_umem *umem, u64 *page_list) { int ret = 0; int i = 0; u32 j = 0; u32 pages_in_chunk = 0; /* The number of pages of a single memory block in umem_chunk */ u32 npages = 0; /* The number of recorded pages */ u32 start_index = 0; /* page need to be written to mtt */ struct scatterlist *sg = NULL; u64 page_size = BIT(mtt->buf_page_shift); u64 page_mask = ~(page_size - 1); u64 dma_addr; for_each_sgtable_dma_sg(&umem->sgt_append.sgt, sg, i) { /* * Calculate the number of pages in a memory block, * the page size is 1 << page_shift */ dma_addr = sg_dma_address(sg) & page_mask; pages_in_chunk = DIV_ROUND_UP(sg_dma_len(sg), page_size); for (j = 0; j < pages_in_chunk; ++j) { page_list[npages] = dma_addr + (page_size * j); npages++; /* * The size of the memory pointed to by page_list is one page, * which can store up to PAGE_SIZE / sizeof(u64) pas. After a page is full, * mtt needs to be written, else continue */ if (npages != PAGE_SIZE / sizeof(u64)) continue; ret = hmm_rdma_write_mtt(rdev->hwdev, mtt, start_index, npages, page_list, SERVICE_T_ROCE); if (ret) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to write mtt, func_id(%u)\n", __func__, rdev->glb_func_id); return ret; } start_index += npages; npages = 0; } } if (npages != 0) { ret = hmm_rdma_write_mtt(rdev->hwdev, mtt, start_index, npages, page_list, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to write mtt, ret(%d), start_index(%u), func_id(%u)\n", __func__, ret, start_index, rdev->glb_func_id); } } return ret; } int roce3_umem_write_mtt(struct roce3_device *rdev, struct rdma_mtt *mtt, struct ib_umem *umem) { int ret = 0; u64 *page_list = NULL; /* page_list to write to mtt */ ret = roce3_umem_write_mtt_check(rdev, mtt, umem); if (ret != 0) return ret; page_list = kzalloc(PAGE_SIZE, GFP_KERNEL); if (page_list == NULL) return -ENOMEM; ret = roce3_umem_write_mtt_update(rdev, mtt, umem, page_list); kfree(page_list); return ret; } /* **************************************************************************** Prototype : roce3_buf_write_mtt Description : roce3_buf_write_mtt Input : struct roce3_device *rdev struct rdma_mtt *mtt struct tag_cqm_buf *buf Output : None 1.Date : 2015/4/24 Modification : Created function **************************************************************************** */ int roce3_buf_write_mtt(struct roce3_device *rdev, struct rdma_mtt *mtt, struct tag_cqm_buf *buf) { u64 *page_list = NULL; int ret = 0; u32 i = 0; if ((rdev == NULL) || (mtt == NULL) || (buf == NULL)) { pr_err("[ROCE, ERR] %s: Rdev or mtt or buf is null\n", __func__); return (-EINVAL); } page_list = kzalloc(buf->buf_number * sizeof(*page_list), GFP_KERNEL); if (page_list == NULL) return (-ENOMEM); /* Each buf is written to MTT as a page, buf_size is 2^n times PAGE_SIZE */ for (i = 0; i < buf->buf_number; ++i) page_list[i] = buf->buf_list[i].pa; ret = hmm_rdma_write_mtt(rdev->hwdev, mtt, 0, buf->buf_number, page_list, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to write mtt, func_id(%d)\n", __func__, rdev->glb_func_id); } kfree(page_list); return ret; } int roce3_user_mr_reg(struct roce3_device *rdev, struct roce3_mr *mr, u32 pdn, u64 virt_addr, u64 length, int access) { int ret = 0; u32 npages = 0; u32 page_shift = PAGE_SHIFT; struct hinic3_hwdev *hwdev = (struct hinic3_hwdev *)rdev->hwdev; if (hwdev == NULL) { pr_err("[HMM, ERR] %s(%d): hwdev is null\n", __func__, __LINE__); return 0; } mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE; npages = (u32)ib_umem_num_pages(mr->umem); #ifdef CONFIG_CENTRALIZED_STORAGE if (mr->umem->is_umm_mem) { page_shift = PAGE_SHIFT_2M; npages = ib_umem_num_dma_blocks(mr->umem, BIT(page_shift)); } #endif ret = roce3_alloc_tpt(rdev, &mr->rdmamr, npages, page_shift); if (ret != 0) { dev_err(hwdev->dev_hdl, "[ROCE, ERR] %s(%d): Failed to alloc mpt and mtt, func_id(%u)\n", __func__, __LINE__, hinic3_global_func_id(hwdev)); goto err_alloc_tpt; } roce3_set_rdma_mr(&mr->rdmamr, RDMA_USER_MR, pdn, virt_addr, length, (u32)access); ret = roce3_umem_write_mtt(rdev, &mr->rdmamr.mtt, mr->umem); if (ret != 0) { dev_err(hwdev->dev_hdl, "[ROCE, ERR] %s(%d): Failed to write mtt, func_id(%u)\n", __func__, __LINE__, hinic3_global_func_id(hwdev)); goto err_write_mtt; } ret = hmm_rdma_enable_mr_mpt(hwdev, &mr->rdmamr, HINIC3_CHANNEL_ROCE); if (ret != 0) { dev_err(hwdev->dev_hdl, "[ROCE, ERR] %s(%d): Failed to enable mpt of user mr, func_id(%u)\n", __func__, __LINE__, hinic3_global_func_id(hwdev)); goto err_write_mtt; } return 0; err_write_mtt: roce3_free_tpt(rdev, &mr->rdmamr); err_alloc_tpt: return ret; } static int roce3_check_mr_param(struct ib_pd *ibpd) { struct roce3_device *rdev = NULL; if (ibpd == NULL) { pr_err("[ROCE, ERR] %s: Ibpd is null\n", __func__); return -EINVAL; } rdev = to_roce3_dev(ibpd->device); if (roce3_hca_is_present(rdev) == 0) { pr_err("[ROCE] %s: HCA not present(return fail), func_id(%u)\n", __func__, rdev->glb_func_id); return -EPERM; } return 0; } /* **************************************************************************** Prototype : roce3_reg_user_mr Description : register MR for user Input : struct ib_pd *ibpd u64 start u64 length u64 virt_addr int access struct ib_udata *udata Output : None 1.Date : 2015/4/24 Modification : Created function **************************************************************************** */ struct ib_mr *roce3_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length, u64 virt_addr, int access, struct ib_udata *udata) { int ret; struct roce3_mr *mr = NULL; struct roce3_device *rdev = NULL; struct roce3_pd *pd; ret = roce3_check_mr_param(ibpd); if (ret != 0) goto err_out; pd = to_roce3_pd(ibpd); rdev = to_roce3_dev(ibpd->device); mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (mr == NULL) { ret = -ENOMEM; dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc memory for roce mr, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_out; } mr->umem = ib_umem_get(&rdev->ib_dev, start, (size_t)length, access); if (IS_ERR(mr->umem)) { ret = (int)PTR_ERR(mr->umem); dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get ib umem, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_get_umem; } ret = roce3_user_mr_reg(rdev, mr, pd->pdn, virt_addr, length, access); if (ret != 0) goto err_mr_update; mr->ibmr.lkey = mr->rdmamr.key; mr->ibmr.rkey = mr->rdmamr.key; return &mr->ibmr; err_mr_update: ib_umem_release(mr->umem); err_get_umem: kfree(mr); err_out: return (struct ib_mr *)ERR_PTR((long)ret); } int roce3_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) { int ret = 0; struct roce3_mr *mr = NULL; struct roce3_device *rdev = NULL; if (ibmr == NULL) { pr_err("[ROCE, ERR] %s: Ibmr is null\n", __func__); return -EINVAL; } mr = to_roce3_mr(ibmr); rdev = to_roce3_dev(ibmr->device); roce3_free_priv_pages(mr); ret = hmm_rdma_disable_mr_mpt(rdev->hwdev, &mr->rdmamr, SERVICE_T_ROCE, HINIC3_CHANNEL_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to disable mpt of mr, ret(%d), func_id(%d)\n", __func__, ret, rdev->glb_func_id); dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Mr may has mw bind on it, mr_key(%#x), func_id(%d)\n", __func__, mr->rdmamr.key, rdev->glb_func_id); if (ret == (-RDMA_CMDQ_TIMEOUT)) rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT; return ret; } roce3_free_tpt(rdev, &mr->rdmamr); if (mr->umem) ib_umem_release(mr->umem); return 0; } static void roce3_err_enable_mpt_handler(void *hwdev, struct roce3_mw *mw) { hmm_rdma_mpt_free(hwdev, &mw->rdmamw.mpt); mw->rdmamw.enabled = RDMA_MPT_DISABLED; } int roce3_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata) { int ret; struct roce3_mw *mw = to_roce3_mw(ibmw); struct roce3_pd *pd = to_roce3_pd(ibmw->pd); struct roce3_device *rdev = to_roce3_dev(ibmw->device); if (roce3_hca_is_present(rdev) == 0) { dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n", __func__, rdev->glb_func_id); return -EPERM; } ret = hmm_rdma_mpt_alloc(rdev->hwdev, &mw->rdmamw.mpt, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc mpt, func_id(%u)\n", __func__, rdev->glb_func_id); goto err; } roce3_set_rdma_mw(&mw->rdmamw, pd->pdn, ibmw->type); ret = roce3_rdma_enable_mw_mpt(rdev->hwdev, &mw->rdmamw, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to enable mpt of mw, func_id(%u)\n", __func__, rdev->glb_func_id); if (ret == (-RDMA_CMDQ_TIMEOUT)) rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT; goto err_enable_mpt; } mw->ibmw.rkey = mw->rdmamw.key; return 0; err_enable_mpt: roce3_err_enable_mpt_handler(rdev->hwdev, mw); err: return ret; } int roce3_dealloc_mw(struct ib_mw *ibmw) { int ret = 0; struct roce3_mw *mw = NULL; struct roce3_device *rdev = NULL; if (ibmw == NULL) { pr_err("[ROCE, ERR] %s: Ibmw is null\n", __func__); return -EINVAL; } mw = to_roce3_mw(ibmw); rdev = to_roce3_dev(ibmw->device); ret = roce3_rdma_disable_mw_mpt(rdev->hwdev, &mw->rdmamw, SERVICE_T_ROCE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to disable mpt of mw, func_id(%d)\n", __func__, rdev->glb_func_id); if (ret == (-RDMA_CMDQ_TIMEOUT)) rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT; return ret; } hmm_rdma_mpt_free(rdev->hwdev, &mw->rdmamw.mpt); mw->rdmamw.enabled = RDMA_MPT_DISABLED; return 0; }