1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright(c) 2016 Intel Corporation. 4 */ 5 6 #include <linux/slab.h> 7 #include <linux/vmalloc.h> 8 #include <linux/mm.h> 9 #include <rdma/uverbs_ioctl.h> 10 #include "mmap.h" 11 12 /* number of reserved mmaps for the driver */ 13 #define MMAP_RESERVED 256 14 /* start point for dynamic offsets */ 15 #define MMAP_OFFSET_START (MMAP_RESERVED * PAGE_SIZE) 16 17 /** 18 * rvt_mmap_init - init link list and lock for mem map 19 * @rdi: rvt dev struct 20 */ 21 void rvt_mmap_init(struct rvt_dev_info *rdi) 22 { 23 INIT_LIST_HEAD(&rdi->pending_mmaps); 24 spin_lock_init(&rdi->pending_lock); 25 rdi->mmap_offset = MMAP_OFFSET_START; 26 spin_lock_init(&rdi->mmap_offset_lock); 27 } 28 29 /** 30 * rvt_release_mmap_info - free mmap info structure 31 * @ref: a pointer to the kref within struct rvt_mmap_info 32 */ 33 void rvt_release_mmap_info(struct kref *ref) 34 { 35 struct rvt_mmap_info *ip = 36 container_of(ref, struct rvt_mmap_info, ref); 37 struct rvt_dev_info *rdi = ib_to_rvt(ip->context->device); 38 39 spin_lock_irq(&rdi->pending_lock); 40 list_del(&ip->pending_mmaps); 41 spin_unlock_irq(&rdi->pending_lock); 42 43 vfree(ip->obj); 44 kfree(ip); 45 } 46 47 static void rvt_vma_open(struct vm_area_struct *vma) 48 { 49 struct rvt_mmap_info *ip = vma->vm_private_data; 50 51 kref_get(&ip->ref); 52 } 53 54 static void rvt_vma_close(struct vm_area_struct *vma) 55 { 56 struct rvt_mmap_info *ip = vma->vm_private_data; 57 58 kref_put(&ip->ref, rvt_release_mmap_info); 59 } 60 61 static const struct vm_operations_struct rvt_vm_ops = { 62 .open = rvt_vma_open, 63 .close = rvt_vma_close, 64 }; 65 66 /** 67 * rvt_mmap - create a new mmap region 68 * @context: the IB user context of the process making the mmap() call 69 * @vma: the VMA to be initialized 70 * 71 * Return: zero if the mmap is OK. Otherwise, return an errno. 72 */ 73 int rvt_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) 74 { 75 struct rvt_dev_info *rdi = ib_to_rvt(context->device); 76 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 77 unsigned long size = vma->vm_end - vma->vm_start; 78 struct rvt_mmap_info *ip, *pp; 79 int ret = -EINVAL; 80 81 /* call driver if in reserved range */ 82 if (offset < MMAP_OFFSET_START) { 83 if (rdi->driver_f.mmap) 84 return rdi->driver_f.mmap(context, vma); 85 return -EINVAL; 86 } 87 88 /* 89 * Search the device's list of objects waiting for a mmap call. 90 * Normally, this list is very short since a call to create a 91 * CQ, QP, or SRQ is soon followed by a call to mmap(). 92 */ 93 spin_lock_irq(&rdi->pending_lock); 94 list_for_each_entry_safe(ip, pp, &rdi->pending_mmaps, 95 pending_mmaps) { 96 /* Only the creator is allowed to mmap the object */ 97 if (context != ip->context || (__u64)offset != ip->offset) 98 continue; 99 /* Don't allow a mmap larger than the object. */ 100 if (size > ip->size) 101 break; 102 103 list_del_init(&ip->pending_mmaps); 104 spin_unlock_irq(&rdi->pending_lock); 105 106 ret = remap_vmalloc_range(vma, ip->obj, 0); 107 if (ret) 108 goto done; 109 vma->vm_ops = &rvt_vm_ops; 110 vma->vm_private_data = ip; 111 rvt_vma_open(vma); 112 goto done; 113 } 114 spin_unlock_irq(&rdi->pending_lock); 115 done: 116 return ret; 117 } 118 119 /** 120 * rvt_create_mmap_info - allocate information for hfi1_mmap 121 * @rdi: rvt dev struct 122 * @size: size in bytes to map 123 * @udata: user data (must be valid!) 124 * @obj: opaque pointer to a cq, wq etc 125 * 126 * Return: rvt_mmap struct on success, ERR_PTR on failure 127 */ 128 struct rvt_mmap_info *rvt_create_mmap_info(struct rvt_dev_info *rdi, u32 size, 129 struct ib_udata *udata, void *obj) 130 { 131 struct rvt_mmap_info *ip; 132 133 if (!udata) 134 return ERR_PTR(-EINVAL); 135 136 ip = kmalloc_node(sizeof(*ip), GFP_KERNEL, rdi->dparms.node); 137 if (!ip) 138 return ERR_PTR(-ENOMEM); 139 140 size = PAGE_ALIGN(size); 141 142 spin_lock_irq(&rdi->mmap_offset_lock); 143 if (rdi->mmap_offset == 0) 144 rdi->mmap_offset = MMAP_OFFSET_START; 145 ip->offset = rdi->mmap_offset; 146 rdi->mmap_offset += PAGE_SIZE; 147 spin_unlock_irq(&rdi->mmap_offset_lock); 148 149 INIT_LIST_HEAD(&ip->pending_mmaps); 150 ip->size = size; 151 ip->context = 152 container_of(udata, struct uverbs_attr_bundle, driver_udata) 153 ->context; 154 ip->obj = obj; 155 kref_init(&ip->ref); 156 157 return ip; 158 } 159 160 /** 161 * rvt_update_mmap_info - update a mem map 162 * @rdi: rvt dev struct 163 * @ip: mmap info pointer 164 * @size: size to grow by 165 * @obj: opaque pointer to cq, wq, etc. 166 */ 167 void rvt_update_mmap_info(struct rvt_dev_info *rdi, struct rvt_mmap_info *ip, 168 u32 size, void *obj) 169 { 170 size = PAGE_ALIGN(size); 171 172 spin_lock_irq(&rdi->mmap_offset_lock); 173 if (rdi->mmap_offset == 0) 174 rdi->mmap_offset = MMAP_OFFSET_START; 175 ip->offset = rdi->mmap_offset; 176 rdi->mmap_offset += PAGE_SIZE; 177 spin_unlock_irq(&rdi->mmap_offset_lock); 178 179 ip->size = size; 180 ip->obj = obj; 181 } 182