linux/drivers/staging/rdma/hfi1/user_pages.c
<<
>>
Prefs
   1/*
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2015 Intel Corporation.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of version 2 of the GNU General Public License as
  12 * published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * BSD LICENSE
  20 *
  21 * Copyright(c) 2015 Intel Corporation.
  22 *
  23 * Redistribution and use in source and binary forms, with or without
  24 * modification, are permitted provided that the following conditions
  25 * are met:
  26 *
  27 *  - Redistributions of source code must retain the above copyright
  28 *    notice, this list of conditions and the following disclaimer.
  29 *  - Redistributions in binary form must reproduce the above copyright
  30 *    notice, this list of conditions and the following disclaimer in
  31 *    the documentation and/or other materials provided with the
  32 *    distribution.
  33 *  - Neither the name of Intel Corporation nor the names of its
  34 *    contributors may be used to endorse or promote products derived
  35 *    from this software without specific prior written permission.
  36 *
  37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  48 *
  49 */
  50
  51#include <linux/mm.h>
  52#include <linux/device.h>
  53
  54#include "hfi.h"
  55
  56static void __hfi1_release_user_pages(struct page **p, size_t num_pages,
  57                                      int dirty)
  58{
  59        size_t i;
  60
  61        for (i = 0; i < num_pages; i++) {
  62                if (dirty)
  63                        set_page_dirty_lock(p[i]);
  64                put_page(p[i]);
  65        }
  66}
  67
  68/*
  69 * Call with current->mm->mmap_sem held.
  70 */
  71static int __hfi1_get_user_pages(unsigned long start_page, size_t num_pages,
  72                                 struct page **p)
  73{
  74        unsigned long lock_limit;
  75        size_t got;
  76        int ret;
  77
  78        lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
  79
  80        if (num_pages > lock_limit && !capable(CAP_IPC_LOCK)) {
  81                ret = -ENOMEM;
  82                goto bail;
  83        }
  84
  85        for (got = 0; got < num_pages; got += ret) {
  86                ret = get_user_pages(current, current->mm,
  87                                     start_page + got * PAGE_SIZE,
  88                                     num_pages - got, 1, 1,
  89                                     p + got, NULL);
  90                if (ret < 0)
  91                        goto bail_release;
  92        }
  93
  94        current->mm->pinned_vm += num_pages;
  95
  96        ret = 0;
  97        goto bail;
  98
  99bail_release:
 100        __hfi1_release_user_pages(p, got, 0);
 101bail:
 102        return ret;
 103}
 104
 105/**
 106 * hfi1_map_page - a safety wrapper around pci_map_page()
 107 *
 108 */
 109dma_addr_t hfi1_map_page(struct pci_dev *hwdev, struct page *page,
 110                         unsigned long offset, size_t size, int direction)
 111{
 112        dma_addr_t phys;
 113
 114        phys = pci_map_page(hwdev, page, offset, size, direction);
 115
 116        return phys;
 117}
 118
 119/**
 120 * hfi1_get_user_pages - lock user pages into memory
 121 * @start_page: the start page
 122 * @num_pages: the number of pages
 123 * @p: the output page structures
 124 *
 125 * This function takes a given start page (page aligned user virtual
 126 * address) and pins it and the following specified number of pages.  For
 127 * now, num_pages is always 1, but that will probably change at some point
 128 * (because caller is doing expected sends on a single virtually contiguous
 129 * buffer, so we can do all pages at once).
 130 */
 131int hfi1_get_user_pages(unsigned long start_page, size_t num_pages,
 132                        struct page **p)
 133{
 134        int ret;
 135
 136        down_write(&current->mm->mmap_sem);
 137
 138        ret = __hfi1_get_user_pages(start_page, num_pages, p);
 139
 140        up_write(&current->mm->mmap_sem);
 141
 142        return ret;
 143}
 144
 145void hfi1_release_user_pages(struct page **p, size_t num_pages)
 146{
 147        if (current->mm) /* during close after signal, mm can be NULL */
 148                down_write(&current->mm->mmap_sem);
 149
 150        __hfi1_release_user_pages(p, num_pages, 1);
 151
 152        if (current->mm) {
 153                current->mm->pinned_vm -= num_pages;
 154                up_write(&current->mm->mmap_sem);
 155        }
 156}
 157