18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2012-2016 VMware, Inc.  All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
58c2ecf20Sopenharmony_ci * modify it under the terms of EITHER the GNU General Public License
68c2ecf20Sopenharmony_ci * version 2 as published by the Free Software Foundation or the BSD
78c2ecf20Sopenharmony_ci * 2-Clause License. This program is distributed in the hope that it
88c2ecf20Sopenharmony_ci * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED
98c2ecf20Sopenharmony_ci * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
108c2ecf20Sopenharmony_ci * See the GNU General Public License version 2 for more details at
118c2ecf20Sopenharmony_ci * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License
148c2ecf20Sopenharmony_ci * along with this program available in the file COPYING in the main
158c2ecf20Sopenharmony_ci * directory of this source tree.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * The BSD 2-Clause License
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
208c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
218c2ecf20Sopenharmony_ci *     conditions are met:
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
248c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
258c2ecf20Sopenharmony_ci *        disclaimer.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
288c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
298c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
308c2ecf20Sopenharmony_ci *        provided with the distribution.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
338c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
348c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
358c2ecf20Sopenharmony_ci * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
368c2ecf20Sopenharmony_ci * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
378c2ecf20Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
388c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
398c2ecf20Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
408c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
418c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
428c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
438c2ecf20Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include <linux/list.h>
478c2ecf20Sopenharmony_ci#include <linux/slab.h>
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#include "pvrdma.h"
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/**
528c2ecf20Sopenharmony_ci * pvrdma_get_dma_mr - get a DMA memory region
538c2ecf20Sopenharmony_ci * @pd: protection domain
548c2ecf20Sopenharmony_ci * @acc: access flags
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * @return: ib_mr pointer on success, otherwise returns an errno.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_cistruct ib_mr *pvrdma_get_dma_mr(struct ib_pd *pd, int acc)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct pvrdma_dev *dev = to_vdev(pd->device);
618c2ecf20Sopenharmony_ci	struct pvrdma_user_mr *mr;
628c2ecf20Sopenharmony_ci	union pvrdma_cmd_req req;
638c2ecf20Sopenharmony_ci	union pvrdma_cmd_resp rsp;
648c2ecf20Sopenharmony_ci	struct pvrdma_cmd_create_mr *cmd = &req.create_mr;
658c2ecf20Sopenharmony_ci	struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp;
668c2ecf20Sopenharmony_ci	int ret;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* Support only LOCAL_WRITE flag for DMA MRs */
698c2ecf20Sopenharmony_ci	if (acc & ~IB_ACCESS_LOCAL_WRITE) {
708c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
718c2ecf20Sopenharmony_ci			 "unsupported dma mr access flags %#x\n", acc);
728c2ecf20Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
768c2ecf20Sopenharmony_ci	if (!mr)
778c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
808c2ecf20Sopenharmony_ci	cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR;
818c2ecf20Sopenharmony_ci	cmd->pd_handle = to_vpd(pd)->pd_handle;
828c2ecf20Sopenharmony_ci	cmd->access_flags = acc;
838c2ecf20Sopenharmony_ci	cmd->flags = PVRDMA_MR_FLAG_DMA;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP);
868c2ecf20Sopenharmony_ci	if (ret < 0) {
878c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
888c2ecf20Sopenharmony_ci			 "could not get DMA mem region, error: %d\n", ret);
898c2ecf20Sopenharmony_ci		kfree(mr);
908c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	mr->mmr.mr_handle = resp->mr_handle;
948c2ecf20Sopenharmony_ci	mr->ibmr.lkey = resp->lkey;
958c2ecf20Sopenharmony_ci	mr->ibmr.rkey = resp->rkey;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return &mr->ibmr;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/**
1018c2ecf20Sopenharmony_ci * pvrdma_reg_user_mr - register a userspace memory region
1028c2ecf20Sopenharmony_ci * @pd: protection domain
1038c2ecf20Sopenharmony_ci * @start: starting address
1048c2ecf20Sopenharmony_ci * @length: length of region
1058c2ecf20Sopenharmony_ci * @virt_addr: I/O virtual address
1068c2ecf20Sopenharmony_ci * @access_flags: access flags for memory region
1078c2ecf20Sopenharmony_ci * @udata: user data
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * @return: ib_mr pointer on success, otherwise returns an errno.
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_cistruct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
1128c2ecf20Sopenharmony_ci				 u64 virt_addr, int access_flags,
1138c2ecf20Sopenharmony_ci				 struct ib_udata *udata)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct pvrdma_dev *dev = to_vdev(pd->device);
1168c2ecf20Sopenharmony_ci	struct pvrdma_user_mr *mr = NULL;
1178c2ecf20Sopenharmony_ci	struct ib_umem *umem;
1188c2ecf20Sopenharmony_ci	union pvrdma_cmd_req req;
1198c2ecf20Sopenharmony_ci	union pvrdma_cmd_resp rsp;
1208c2ecf20Sopenharmony_ci	struct pvrdma_cmd_create_mr *cmd = &req.create_mr;
1218c2ecf20Sopenharmony_ci	struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp;
1228c2ecf20Sopenharmony_ci	int ret, npages;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (length == 0 || length > dev->dsr->caps.max_mr_size) {
1258c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev, "invalid mem region length\n");
1268c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	umem = ib_umem_get(pd->device, start, length, access_flags);
1308c2ecf20Sopenharmony_ci	if (IS_ERR(umem)) {
1318c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
1328c2ecf20Sopenharmony_ci			 "could not get umem for mem region\n");
1338c2ecf20Sopenharmony_ci		return ERR_CAST(umem);
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	npages = ib_umem_num_dma_blocks(umem, PAGE_SIZE);
1378c2ecf20Sopenharmony_ci	if (npages < 0 || npages > PVRDMA_PAGE_DIR_MAX_PAGES) {
1388c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev, "overflow %d pages in mem region\n",
1398c2ecf20Sopenharmony_ci			 npages);
1408c2ecf20Sopenharmony_ci		ret = -EINVAL;
1418c2ecf20Sopenharmony_ci		goto err_umem;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
1458c2ecf20Sopenharmony_ci	if (!mr) {
1468c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1478c2ecf20Sopenharmony_ci		goto err_umem;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	mr->mmr.iova = virt_addr;
1518c2ecf20Sopenharmony_ci	mr->mmr.size = length;
1528c2ecf20Sopenharmony_ci	mr->umem = umem;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ret = pvrdma_page_dir_init(dev, &mr->pdir, npages, false);
1558c2ecf20Sopenharmony_ci	if (ret) {
1568c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
1578c2ecf20Sopenharmony_ci			 "could not allocate page directory\n");
1588c2ecf20Sopenharmony_ci		goto err_umem;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	ret = pvrdma_page_dir_insert_umem(&mr->pdir, mr->umem, 0);
1628c2ecf20Sopenharmony_ci	if (ret)
1638c2ecf20Sopenharmony_ci		goto err_pdir;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
1668c2ecf20Sopenharmony_ci	cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR;
1678c2ecf20Sopenharmony_ci	cmd->start = start;
1688c2ecf20Sopenharmony_ci	cmd->length = length;
1698c2ecf20Sopenharmony_ci	cmd->pd_handle = to_vpd(pd)->pd_handle;
1708c2ecf20Sopenharmony_ci	cmd->access_flags = access_flags;
1718c2ecf20Sopenharmony_ci	cmd->nchunks = npages;
1728c2ecf20Sopenharmony_ci	cmd->pdir_dma = mr->pdir.dir_dma;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP);
1758c2ecf20Sopenharmony_ci	if (ret < 0) {
1768c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
1778c2ecf20Sopenharmony_ci			 "could not register mem region, error: %d\n", ret);
1788c2ecf20Sopenharmony_ci		goto err_pdir;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	mr->mmr.mr_handle = resp->mr_handle;
1828c2ecf20Sopenharmony_ci	mr->ibmr.lkey = resp->lkey;
1838c2ecf20Sopenharmony_ci	mr->ibmr.rkey = resp->rkey;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return &mr->ibmr;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cierr_pdir:
1888c2ecf20Sopenharmony_ci	pvrdma_page_dir_cleanup(dev, &mr->pdir);
1898c2ecf20Sopenharmony_cierr_umem:
1908c2ecf20Sopenharmony_ci	ib_umem_release(umem);
1918c2ecf20Sopenharmony_ci	kfree(mr);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/**
1978c2ecf20Sopenharmony_ci * pvrdma_alloc_mr - allocate a memory region
1988c2ecf20Sopenharmony_ci * @pd: protection domain
1998c2ecf20Sopenharmony_ci * @mr_type: type of memory region
2008c2ecf20Sopenharmony_ci * @max_num_sg: maximum number of pages
2018c2ecf20Sopenharmony_ci *
2028c2ecf20Sopenharmony_ci * @return: ib_mr pointer on success, otherwise returns an errno.
2038c2ecf20Sopenharmony_ci */
2048c2ecf20Sopenharmony_cistruct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
2058c2ecf20Sopenharmony_ci			      u32 max_num_sg)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct pvrdma_dev *dev = to_vdev(pd->device);
2088c2ecf20Sopenharmony_ci	struct pvrdma_user_mr *mr;
2098c2ecf20Sopenharmony_ci	union pvrdma_cmd_req req;
2108c2ecf20Sopenharmony_ci	union pvrdma_cmd_resp rsp;
2118c2ecf20Sopenharmony_ci	struct pvrdma_cmd_create_mr *cmd = &req.create_mr;
2128c2ecf20Sopenharmony_ci	struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp;
2138c2ecf20Sopenharmony_ci	int size = max_num_sg * sizeof(u64);
2148c2ecf20Sopenharmony_ci	int ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (mr_type != IB_MR_TYPE_MEM_REG ||
2178c2ecf20Sopenharmony_ci	    max_num_sg > PVRDMA_MAX_FAST_REG_PAGES)
2188c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
2218c2ecf20Sopenharmony_ci	if (!mr)
2228c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	mr->pages = kzalloc(size, GFP_KERNEL);
2258c2ecf20Sopenharmony_ci	if (!mr->pages) {
2268c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2278c2ecf20Sopenharmony_ci		goto freemr;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	ret = pvrdma_page_dir_init(dev, &mr->pdir, max_num_sg, false);
2318c2ecf20Sopenharmony_ci	if (ret) {
2328c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
2338c2ecf20Sopenharmony_ci			 "failed to allocate page dir for mr\n");
2348c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2358c2ecf20Sopenharmony_ci		goto freepages;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
2398c2ecf20Sopenharmony_ci	cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR;
2408c2ecf20Sopenharmony_ci	cmd->pd_handle = to_vpd(pd)->pd_handle;
2418c2ecf20Sopenharmony_ci	cmd->access_flags = 0;
2428c2ecf20Sopenharmony_ci	cmd->flags = PVRDMA_MR_FLAG_FRMR;
2438c2ecf20Sopenharmony_ci	cmd->nchunks = max_num_sg;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP);
2468c2ecf20Sopenharmony_ci	if (ret < 0) {
2478c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
2488c2ecf20Sopenharmony_ci			 "could not create FR mem region, error: %d\n", ret);
2498c2ecf20Sopenharmony_ci		goto freepdir;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	mr->max_pages = max_num_sg;
2538c2ecf20Sopenharmony_ci	mr->mmr.mr_handle = resp->mr_handle;
2548c2ecf20Sopenharmony_ci	mr->ibmr.lkey = resp->lkey;
2558c2ecf20Sopenharmony_ci	mr->ibmr.rkey = resp->rkey;
2568c2ecf20Sopenharmony_ci	mr->page_shift = PAGE_SHIFT;
2578c2ecf20Sopenharmony_ci	mr->umem = NULL;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return &mr->ibmr;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cifreepdir:
2628c2ecf20Sopenharmony_ci	pvrdma_page_dir_cleanup(dev, &mr->pdir);
2638c2ecf20Sopenharmony_cifreepages:
2648c2ecf20Sopenharmony_ci	kfree(mr->pages);
2658c2ecf20Sopenharmony_cifreemr:
2668c2ecf20Sopenharmony_ci	kfree(mr);
2678c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/**
2718c2ecf20Sopenharmony_ci * pvrdma_dereg_mr - deregister a memory region
2728c2ecf20Sopenharmony_ci * @ibmr: memory region
2738c2ecf20Sopenharmony_ci * @udata: pointer to user data
2748c2ecf20Sopenharmony_ci *
2758c2ecf20Sopenharmony_ci * @return: 0 on success.
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_ciint pvrdma_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct pvrdma_user_mr *mr = to_vmr(ibmr);
2808c2ecf20Sopenharmony_ci	struct pvrdma_dev *dev = to_vdev(ibmr->device);
2818c2ecf20Sopenharmony_ci	union pvrdma_cmd_req req;
2828c2ecf20Sopenharmony_ci	struct pvrdma_cmd_destroy_mr *cmd = &req.destroy_mr;
2838c2ecf20Sopenharmony_ci	int ret;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
2868c2ecf20Sopenharmony_ci	cmd->hdr.cmd = PVRDMA_CMD_DESTROY_MR;
2878c2ecf20Sopenharmony_ci	cmd->mr_handle = mr->mmr.mr_handle;
2888c2ecf20Sopenharmony_ci	ret = pvrdma_cmd_post(dev, &req, NULL, 0);
2898c2ecf20Sopenharmony_ci	if (ret < 0)
2908c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev,
2918c2ecf20Sopenharmony_ci			 "could not deregister mem region, error: %d\n", ret);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	pvrdma_page_dir_cleanup(dev, &mr->pdir);
2948c2ecf20Sopenharmony_ci	ib_umem_release(mr->umem);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	kfree(mr->pages);
2978c2ecf20Sopenharmony_ci	kfree(mr);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return 0;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int pvrdma_set_page(struct ib_mr *ibmr, u64 addr)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct pvrdma_user_mr *mr = to_vmr(ibmr);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (mr->npages == mr->max_pages)
3078c2ecf20Sopenharmony_ci		return -ENOMEM;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	mr->pages[mr->npages++] = addr;
3108c2ecf20Sopenharmony_ci	return 0;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ciint pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
3148c2ecf20Sopenharmony_ci		     unsigned int *sg_offset)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct pvrdma_user_mr *mr = to_vmr(ibmr);
3178c2ecf20Sopenharmony_ci	struct pvrdma_dev *dev = to_vdev(ibmr->device);
3188c2ecf20Sopenharmony_ci	int ret;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	mr->npages = 0;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, pvrdma_set_page);
3238c2ecf20Sopenharmony_ci	if (ret < 0)
3248c2ecf20Sopenharmony_ci		dev_warn(&dev->pdev->dev, "could not map sg to pages\n");
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return ret;
3278c2ecf20Sopenharmony_ci}
328