1*f48ad614SDennis Dalessandro /* 2*f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation. 3*f48ad614SDennis Dalessandro * 4*f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5*f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6*f48ad614SDennis Dalessandro * 7*f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8*f48ad614SDennis Dalessandro * 9*f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10*f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11*f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12*f48ad614SDennis Dalessandro * 13*f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14*f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15*f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16*f48ad614SDennis Dalessandro * General Public License for more details. 17*f48ad614SDennis Dalessandro * 18*f48ad614SDennis Dalessandro * BSD LICENSE 19*f48ad614SDennis Dalessandro * 20*f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21*f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22*f48ad614SDennis Dalessandro * are met: 23*f48ad614SDennis Dalessandro * 24*f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25*f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26*f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27*f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28*f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29*f48ad614SDennis Dalessandro * distribution. 30*f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31*f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32*f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33*f48ad614SDennis Dalessandro * 34*f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35*f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36*f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37*f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38*f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39*f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40*f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41*f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42*f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43*f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44*f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45*f48ad614SDennis Dalessandro * 46*f48ad614SDennis Dalessandro */ 47*f48ad614SDennis Dalessandro 48*f48ad614SDennis Dalessandro #include <linux/mm.h> 49*f48ad614SDennis Dalessandro #include <linux/sched.h> 50*f48ad614SDennis Dalessandro #include <linux/device.h> 51*f48ad614SDennis Dalessandro #include <linux/module.h> 52*f48ad614SDennis Dalessandro 53*f48ad614SDennis Dalessandro #include "hfi.h" 54*f48ad614SDennis Dalessandro 55*f48ad614SDennis Dalessandro static unsigned long cache_size = 256; 56*f48ad614SDennis Dalessandro module_param(cache_size, ulong, S_IRUGO | S_IWUSR); 57*f48ad614SDennis Dalessandro MODULE_PARM_DESC(cache_size, "Send and receive side cache size limit (in MB)"); 58*f48ad614SDennis Dalessandro 59*f48ad614SDennis Dalessandro /* 60*f48ad614SDennis Dalessandro * Determine whether the caller can pin pages. 61*f48ad614SDennis Dalessandro * 62*f48ad614SDennis Dalessandro * This function should be used in the implementation of buffer caches. 63*f48ad614SDennis Dalessandro * The cache implementation should call this function prior to attempting 64*f48ad614SDennis Dalessandro * to pin buffer pages in order to determine whether they should do so. 65*f48ad614SDennis Dalessandro * The function computes cache limits based on the configured ulimit and 66*f48ad614SDennis Dalessandro * cache size. Use of this function is especially important for caches 67*f48ad614SDennis Dalessandro * which are not limited in any other way (e.g. by HW resources) and, thus, 68*f48ad614SDennis Dalessandro * could keeping caching buffers. 69*f48ad614SDennis Dalessandro * 70*f48ad614SDennis Dalessandro */ 71*f48ad614SDennis Dalessandro bool hfi1_can_pin_pages(struct hfi1_devdata *dd, u32 nlocked, u32 npages) 72*f48ad614SDennis Dalessandro { 73*f48ad614SDennis Dalessandro unsigned long ulimit = rlimit(RLIMIT_MEMLOCK), pinned, cache_limit, 74*f48ad614SDennis Dalessandro size = (cache_size * (1UL << 20)); /* convert to bytes */ 75*f48ad614SDennis Dalessandro unsigned usr_ctxts = dd->num_rcv_contexts - dd->first_user_ctxt; 76*f48ad614SDennis Dalessandro bool can_lock = capable(CAP_IPC_LOCK); 77*f48ad614SDennis Dalessandro 78*f48ad614SDennis Dalessandro /* 79*f48ad614SDennis Dalessandro * Calculate per-cache size. The calculation below uses only a quarter 80*f48ad614SDennis Dalessandro * of the available per-context limit. This leaves space for other 81*f48ad614SDennis Dalessandro * pinning. Should we worry about shared ctxts? 82*f48ad614SDennis Dalessandro */ 83*f48ad614SDennis Dalessandro cache_limit = (ulimit / usr_ctxts) / 4; 84*f48ad614SDennis Dalessandro 85*f48ad614SDennis Dalessandro /* If ulimit isn't set to "unlimited" and is smaller than cache_size. */ 86*f48ad614SDennis Dalessandro if (ulimit != (-1UL) && size > cache_limit) 87*f48ad614SDennis Dalessandro size = cache_limit; 88*f48ad614SDennis Dalessandro 89*f48ad614SDennis Dalessandro /* Convert to number of pages */ 90*f48ad614SDennis Dalessandro size = DIV_ROUND_UP(size, PAGE_SIZE); 91*f48ad614SDennis Dalessandro 92*f48ad614SDennis Dalessandro down_read(¤t->mm->mmap_sem); 93*f48ad614SDennis Dalessandro pinned = current->mm->pinned_vm; 94*f48ad614SDennis Dalessandro up_read(¤t->mm->mmap_sem); 95*f48ad614SDennis Dalessandro 96*f48ad614SDennis Dalessandro /* First, check the absolute limit against all pinned pages. */ 97*f48ad614SDennis Dalessandro if (pinned + npages >= ulimit && !can_lock) 98*f48ad614SDennis Dalessandro return false; 99*f48ad614SDennis Dalessandro 100*f48ad614SDennis Dalessandro return ((nlocked + npages) <= size) || can_lock; 101*f48ad614SDennis Dalessandro } 102*f48ad614SDennis Dalessandro 103*f48ad614SDennis Dalessandro int hfi1_acquire_user_pages(unsigned long vaddr, size_t npages, bool writable, 104*f48ad614SDennis Dalessandro struct page **pages) 105*f48ad614SDennis Dalessandro { 106*f48ad614SDennis Dalessandro int ret; 107*f48ad614SDennis Dalessandro 108*f48ad614SDennis Dalessandro ret = get_user_pages_fast(vaddr, npages, writable, pages); 109*f48ad614SDennis Dalessandro if (ret < 0) 110*f48ad614SDennis Dalessandro return ret; 111*f48ad614SDennis Dalessandro 112*f48ad614SDennis Dalessandro down_write(¤t->mm->mmap_sem); 113*f48ad614SDennis Dalessandro current->mm->pinned_vm += ret; 114*f48ad614SDennis Dalessandro up_write(¤t->mm->mmap_sem); 115*f48ad614SDennis Dalessandro 116*f48ad614SDennis Dalessandro return ret; 117*f48ad614SDennis Dalessandro } 118*f48ad614SDennis Dalessandro 119*f48ad614SDennis Dalessandro void hfi1_release_user_pages(struct mm_struct *mm, struct page **p, 120*f48ad614SDennis Dalessandro size_t npages, bool dirty) 121*f48ad614SDennis Dalessandro { 122*f48ad614SDennis Dalessandro size_t i; 123*f48ad614SDennis Dalessandro 124*f48ad614SDennis Dalessandro for (i = 0; i < npages; i++) { 125*f48ad614SDennis Dalessandro if (dirty) 126*f48ad614SDennis Dalessandro set_page_dirty_lock(p[i]); 127*f48ad614SDennis Dalessandro put_page(p[i]); 128*f48ad614SDennis Dalessandro } 129*f48ad614SDennis Dalessandro 130*f48ad614SDennis Dalessandro if (mm) { /* during close after signal, mm can be NULL */ 131*f48ad614SDennis Dalessandro down_write(&mm->mmap_sem); 132*f48ad614SDennis Dalessandro mm->pinned_vm -= npages; 133*f48ad614SDennis Dalessandro up_write(&mm->mmap_sem); 134*f48ad614SDennis Dalessandro } 135*f48ad614SDennis Dalessandro } 136