cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pvrdma_mr.c (9087B)


      1/*
      2 * Copyright (c) 2012-2016 VMware, Inc.  All rights reserved.
      3 *
      4 * This program is free software; you can redistribute it and/or
      5 * modify it under the terms of EITHER the GNU General Public License
      6 * version 2 as published by the Free Software Foundation or the BSD
      7 * 2-Clause License. This program is distributed in the hope that it
      8 * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED
      9 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
     10 * See the GNU General Public License version 2 for more details at
     11 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html.
     12 *
     13 * You should have received a copy of the GNU General Public License
     14 * along with this program available in the file COPYING in the main
     15 * directory of this source tree.
     16 *
     17 * The BSD 2-Clause License
     18 *
     19 *     Redistribution and use in source and binary forms, with or
     20 *     without modification, are permitted provided that the following
     21 *     conditions are met:
     22 *
     23 *      - Redistributions of source code must retain the above
     24 *        copyright notice, this list of conditions and the following
     25 *        disclaimer.
     26 *
     27 *      - Redistributions in binary form must reproduce the above
     28 *        copyright notice, this list of conditions and the following
     29 *        disclaimer in the documentation and/or other materials
     30 *        provided with the distribution.
     31 *
     32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     35 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     36 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     37 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     39 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     43 * OF THE POSSIBILITY OF SUCH DAMAGE.
     44 */
     45
     46#include <linux/list.h>
     47#include <linux/slab.h>
     48
     49#include "pvrdma.h"
     50
     51/**
     52 * pvrdma_get_dma_mr - get a DMA memory region
     53 * @pd: protection domain
     54 * @acc: access flags
     55 *
     56 * @return: ib_mr pointer on success, otherwise returns an errno.
     57 */
     58struct ib_mr *pvrdma_get_dma_mr(struct ib_pd *pd, int acc)
     59{
     60	struct pvrdma_dev *dev = to_vdev(pd->device);
     61	struct pvrdma_user_mr *mr;
     62	union pvrdma_cmd_req req;
     63	union pvrdma_cmd_resp rsp;
     64	struct pvrdma_cmd_create_mr *cmd = &req.create_mr;
     65	struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp;
     66	int ret;
     67
     68	/* Support only LOCAL_WRITE flag for DMA MRs */
     69	if (acc & ~IB_ACCESS_LOCAL_WRITE) {
     70		dev_warn(&dev->pdev->dev,
     71			 "unsupported dma mr access flags %#x\n", acc);
     72		return ERR_PTR(-EOPNOTSUPP);
     73	}
     74
     75	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
     76	if (!mr)
     77		return ERR_PTR(-ENOMEM);
     78
     79	memset(cmd, 0, sizeof(*cmd));
     80	cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR;
     81	cmd->pd_handle = to_vpd(pd)->pd_handle;
     82	cmd->access_flags = acc;
     83	cmd->flags = PVRDMA_MR_FLAG_DMA;
     84
     85	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP);
     86	if (ret < 0) {
     87		dev_warn(&dev->pdev->dev,
     88			 "could not get DMA mem region, error: %d\n", ret);
     89		kfree(mr);
     90		return ERR_PTR(ret);
     91	}
     92
     93	mr->mmr.mr_handle = resp->mr_handle;
     94	mr->ibmr.lkey = resp->lkey;
     95	mr->ibmr.rkey = resp->rkey;
     96
     97	return &mr->ibmr;
     98}
     99
    100/**
    101 * pvrdma_reg_user_mr - register a userspace memory region
    102 * @pd: protection domain
    103 * @start: starting address
    104 * @length: length of region
    105 * @virt_addr: I/O virtual address
    106 * @access_flags: access flags for memory region
    107 * @udata: user data
    108 *
    109 * @return: ib_mr pointer on success, otherwise returns an errno.
    110 */
    111struct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
    112				 u64 virt_addr, int access_flags,
    113				 struct ib_udata *udata)
    114{
    115	struct pvrdma_dev *dev = to_vdev(pd->device);
    116	struct pvrdma_user_mr *mr = NULL;
    117	struct ib_umem *umem;
    118	union pvrdma_cmd_req req;
    119	union pvrdma_cmd_resp rsp;
    120	struct pvrdma_cmd_create_mr *cmd = &req.create_mr;
    121	struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp;
    122	int ret, npages;
    123
    124	if (length == 0 || length > dev->dsr->caps.max_mr_size) {
    125		dev_warn(&dev->pdev->dev, "invalid mem region length\n");
    126		return ERR_PTR(-EINVAL);
    127	}
    128
    129	umem = ib_umem_get(pd->device, start, length, access_flags);
    130	if (IS_ERR(umem)) {
    131		dev_warn(&dev->pdev->dev,
    132			 "could not get umem for mem region\n");
    133		return ERR_CAST(umem);
    134	}
    135
    136	npages = ib_umem_num_dma_blocks(umem, PAGE_SIZE);
    137	if (npages < 0 || npages > PVRDMA_PAGE_DIR_MAX_PAGES) {
    138		dev_warn(&dev->pdev->dev, "overflow %d pages in mem region\n",
    139			 npages);
    140		ret = -EINVAL;
    141		goto err_umem;
    142	}
    143
    144	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
    145	if (!mr) {
    146		ret = -ENOMEM;
    147		goto err_umem;
    148	}
    149
    150	mr->mmr.iova = virt_addr;
    151	mr->mmr.size = length;
    152	mr->umem = umem;
    153
    154	ret = pvrdma_page_dir_init(dev, &mr->pdir, npages, false);
    155	if (ret) {
    156		dev_warn(&dev->pdev->dev,
    157			 "could not allocate page directory\n");
    158		goto err_umem;
    159	}
    160
    161	ret = pvrdma_page_dir_insert_umem(&mr->pdir, mr->umem, 0);
    162	if (ret)
    163		goto err_pdir;
    164
    165	memset(cmd, 0, sizeof(*cmd));
    166	cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR;
    167	cmd->start = start;
    168	cmd->length = length;
    169	cmd->pd_handle = to_vpd(pd)->pd_handle;
    170	cmd->access_flags = access_flags;
    171	cmd->nchunks = npages;
    172	cmd->pdir_dma = mr->pdir.dir_dma;
    173
    174	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP);
    175	if (ret < 0) {
    176		dev_warn(&dev->pdev->dev,
    177			 "could not register mem region, error: %d\n", ret);
    178		goto err_pdir;
    179	}
    180
    181	mr->mmr.mr_handle = resp->mr_handle;
    182	mr->ibmr.lkey = resp->lkey;
    183	mr->ibmr.rkey = resp->rkey;
    184
    185	return &mr->ibmr;
    186
    187err_pdir:
    188	pvrdma_page_dir_cleanup(dev, &mr->pdir);
    189err_umem:
    190	ib_umem_release(umem);
    191	kfree(mr);
    192
    193	return ERR_PTR(ret);
    194}
    195
    196/**
    197 * pvrdma_alloc_mr - allocate a memory region
    198 * @pd: protection domain
    199 * @mr_type: type of memory region
    200 * @max_num_sg: maximum number of pages
    201 *
    202 * @return: ib_mr pointer on success, otherwise returns an errno.
    203 */
    204struct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
    205			      u32 max_num_sg)
    206{
    207	struct pvrdma_dev *dev = to_vdev(pd->device);
    208	struct pvrdma_user_mr *mr;
    209	union pvrdma_cmd_req req;
    210	union pvrdma_cmd_resp rsp;
    211	struct pvrdma_cmd_create_mr *cmd = &req.create_mr;
    212	struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp;
    213	int size = max_num_sg * sizeof(u64);
    214	int ret;
    215
    216	if (mr_type != IB_MR_TYPE_MEM_REG ||
    217	    max_num_sg > PVRDMA_MAX_FAST_REG_PAGES)
    218		return ERR_PTR(-EINVAL);
    219
    220	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
    221	if (!mr)
    222		return ERR_PTR(-ENOMEM);
    223
    224	mr->pages = kzalloc(size, GFP_KERNEL);
    225	if (!mr->pages) {
    226		ret = -ENOMEM;
    227		goto freemr;
    228	}
    229
    230	ret = pvrdma_page_dir_init(dev, &mr->pdir, max_num_sg, false);
    231	if (ret) {
    232		dev_warn(&dev->pdev->dev,
    233			 "failed to allocate page dir for mr\n");
    234		ret = -ENOMEM;
    235		goto freepages;
    236	}
    237
    238	memset(cmd, 0, sizeof(*cmd));
    239	cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR;
    240	cmd->pd_handle = to_vpd(pd)->pd_handle;
    241	cmd->access_flags = 0;
    242	cmd->flags = PVRDMA_MR_FLAG_FRMR;
    243	cmd->nchunks = max_num_sg;
    244
    245	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP);
    246	if (ret < 0) {
    247		dev_warn(&dev->pdev->dev,
    248			 "could not create FR mem region, error: %d\n", ret);
    249		goto freepdir;
    250	}
    251
    252	mr->max_pages = max_num_sg;
    253	mr->mmr.mr_handle = resp->mr_handle;
    254	mr->ibmr.lkey = resp->lkey;
    255	mr->ibmr.rkey = resp->rkey;
    256	mr->page_shift = PAGE_SHIFT;
    257	mr->umem = NULL;
    258
    259	return &mr->ibmr;
    260
    261freepdir:
    262	pvrdma_page_dir_cleanup(dev, &mr->pdir);
    263freepages:
    264	kfree(mr->pages);
    265freemr:
    266	kfree(mr);
    267	return ERR_PTR(ret);
    268}
    269
    270/**
    271 * pvrdma_dereg_mr - deregister a memory region
    272 * @ibmr: memory region
    273 * @udata: pointer to user data
    274 *
    275 * @return: 0 on success.
    276 */
    277int pvrdma_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
    278{
    279	struct pvrdma_user_mr *mr = to_vmr(ibmr);
    280	struct pvrdma_dev *dev = to_vdev(ibmr->device);
    281	union pvrdma_cmd_req req;
    282	struct pvrdma_cmd_destroy_mr *cmd = &req.destroy_mr;
    283	int ret;
    284
    285	memset(cmd, 0, sizeof(*cmd));
    286	cmd->hdr.cmd = PVRDMA_CMD_DESTROY_MR;
    287	cmd->mr_handle = mr->mmr.mr_handle;
    288	ret = pvrdma_cmd_post(dev, &req, NULL, 0);
    289	if (ret < 0)
    290		dev_warn(&dev->pdev->dev,
    291			 "could not deregister mem region, error: %d\n", ret);
    292
    293	pvrdma_page_dir_cleanup(dev, &mr->pdir);
    294	ib_umem_release(mr->umem);
    295
    296	kfree(mr->pages);
    297	kfree(mr);
    298
    299	return 0;
    300}
    301
    302static int pvrdma_set_page(struct ib_mr *ibmr, u64 addr)
    303{
    304	struct pvrdma_user_mr *mr = to_vmr(ibmr);
    305
    306	if (mr->npages == mr->max_pages)
    307		return -ENOMEM;
    308
    309	mr->pages[mr->npages++] = addr;
    310	return 0;
    311}
    312
    313int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
    314		     unsigned int *sg_offset)
    315{
    316	struct pvrdma_user_mr *mr = to_vmr(ibmr);
    317	struct pvrdma_dev *dev = to_vdev(ibmr->device);
    318	int ret;
    319
    320	mr->npages = 0;
    321
    322	ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, pvrdma_set_page);
    323	if (ret < 0)
    324		dev_warn(&dev->pdev->dev, "could not map sg to pages\n");
    325
    326	return ret;
    327}