at master 322 lines 9.4 kB view raw
1// SPDX-License-Identifier: MIT 2/* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6#include "xe_svm.h" 7#include "xe_userptr.h" 8 9#include <linux/mm.h> 10 11#include "xe_trace_bo.h" 12 13/** 14 * xe_vma_userptr_check_repin() - Advisory check for repin needed 15 * @uvma: The userptr vma 16 * 17 * Check if the userptr vma has been invalidated since last successful 18 * repin. The check is advisory only and can the function can be called 19 * without the vm->svm.gpusvm.notifier_lock held. There is no guarantee that the 20 * vma userptr will remain valid after a lockless check, so typically 21 * the call needs to be followed by a proper check under the notifier_lock. 22 * 23 * Return: 0 if userptr vma is valid, -EAGAIN otherwise; repin recommended. 24 */ 25int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma) 26{ 27 return mmu_interval_check_retry(&uvma->userptr.notifier, 28 uvma->userptr.pages.notifier_seq) ? 29 -EAGAIN : 0; 30} 31 32/** 33 * __xe_vm_userptr_needs_repin() - Check whether the VM does have userptrs 34 * that need repinning. 35 * @vm: The VM. 36 * 37 * This function checks for whether the VM has userptrs that need repinning, 38 * and provides a release-type barrier on the svm.gpusvm.notifier_lock after 39 * checking. 40 * 41 * Return: 0 if there are no userptrs needing repinning, -EAGAIN if there are. 42 */ 43int __xe_vm_userptr_needs_repin(struct xe_vm *vm) 44{ 45 lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock); 46 47 return (list_empty(&vm->userptr.repin_list) && 48 list_empty(&vm->userptr.invalidated)) ? 0 : -EAGAIN; 49} 50 51int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma) 52{ 53 struct xe_vma *vma = &uvma->vma; 54 struct xe_vm *vm = xe_vma_vm(vma); 55 struct xe_device *xe = vm->xe; 56 struct drm_gpusvm_ctx ctx = { 57 .read_only = xe_vma_read_only(vma), 58 .device_private_page_owner = xe_svm_devm_owner(xe), 59 .allow_mixed = true, 60 }; 61 62 lockdep_assert_held(&vm->lock); 63 xe_assert(xe, xe_vma_is_userptr(vma)); 64 65 if (vma->gpuva.flags & XE_VMA_DESTROYED) 66 return 0; 67 68 return drm_gpusvm_get_pages(&vm->svm.gpusvm, &uvma->userptr.pages, 69 uvma->userptr.notifier.mm, 70 &uvma->userptr.notifier, 71 xe_vma_userptr(vma), 72 xe_vma_userptr(vma) + xe_vma_size(vma), 73 &ctx); 74} 75 76static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uvma) 77{ 78 struct xe_userptr *userptr = &uvma->userptr; 79 struct xe_vma *vma = &uvma->vma; 80 struct dma_resv_iter cursor; 81 struct dma_fence *fence; 82 struct drm_gpusvm_ctx ctx = { 83 .in_notifier = true, 84 .read_only = xe_vma_read_only(vma), 85 }; 86 long err; 87 88 /* 89 * Tell exec and rebind worker they need to repin and rebind this 90 * userptr. 91 */ 92 if (!xe_vm_in_fault_mode(vm) && 93 !(vma->gpuva.flags & XE_VMA_DESTROYED)) { 94 spin_lock(&vm->userptr.invalidated_lock); 95 list_move_tail(&userptr->invalidate_link, 96 &vm->userptr.invalidated); 97 spin_unlock(&vm->userptr.invalidated_lock); 98 } 99 100 /* 101 * Preempt fences turn into schedule disables, pipeline these. 102 * Note that even in fault mode, we need to wait for binds and 103 * unbinds to complete, and those are attached as BOOKMARK fences 104 * to the vm. 105 */ 106 dma_resv_iter_begin(&cursor, xe_vm_resv(vm), 107 DMA_RESV_USAGE_BOOKKEEP); 108 dma_resv_for_each_fence_unlocked(&cursor, fence) 109 dma_fence_enable_sw_signaling(fence); 110 dma_resv_iter_end(&cursor); 111 112 err = dma_resv_wait_timeout(xe_vm_resv(vm), 113 DMA_RESV_USAGE_BOOKKEEP, 114 false, MAX_SCHEDULE_TIMEOUT); 115 XE_WARN_ON(err <= 0); 116 117 if (xe_vm_in_fault_mode(vm) && userptr->initial_bind) { 118 err = xe_vm_invalidate_vma(vma); 119 XE_WARN_ON(err); 120 } 121 122 drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages, 123 xe_vma_size(vma) >> PAGE_SHIFT, &ctx); 124} 125 126static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni, 127 const struct mmu_notifier_range *range, 128 unsigned long cur_seq) 129{ 130 struct xe_userptr_vma *uvma = container_of(mni, typeof(*uvma), userptr.notifier); 131 struct xe_vma *vma = &uvma->vma; 132 struct xe_vm *vm = xe_vma_vm(vma); 133 134 xe_assert(vm->xe, xe_vma_is_userptr(vma)); 135 trace_xe_vma_userptr_invalidate(vma); 136 137 if (!mmu_notifier_range_blockable(range)) 138 return false; 139 140 vm_dbg(&xe_vma_vm(vma)->xe->drm, 141 "NOTIFIER: addr=0x%016llx, range=0x%016llx", 142 xe_vma_start(vma), xe_vma_size(vma)); 143 144 down_write(&vm->svm.gpusvm.notifier_lock); 145 mmu_interval_set_seq(mni, cur_seq); 146 147 __vma_userptr_invalidate(vm, uvma); 148 up_write(&vm->svm.gpusvm.notifier_lock); 149 trace_xe_vma_userptr_invalidate_complete(vma); 150 151 return true; 152} 153 154static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { 155 .invalidate = vma_userptr_invalidate, 156}; 157 158#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) 159/** 160 * xe_vma_userptr_force_invalidate() - force invalidate a userptr 161 * @uvma: The userptr vma to invalidate 162 * 163 * Perform a forced userptr invalidation for testing purposes. 164 */ 165void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) 166{ 167 struct xe_vm *vm = xe_vma_vm(&uvma->vma); 168 169 /* Protect against concurrent userptr pinning */ 170 lockdep_assert_held(&vm->lock); 171 /* Protect against concurrent notifiers */ 172 lockdep_assert_held(&vm->svm.gpusvm.notifier_lock); 173 /* 174 * Protect against concurrent instances of this function and 175 * the critical exec sections 176 */ 177 xe_vm_assert_held(vm); 178 179 if (!mmu_interval_read_retry(&uvma->userptr.notifier, 180 uvma->userptr.pages.notifier_seq)) 181 uvma->userptr.pages.notifier_seq -= 2; 182 __vma_userptr_invalidate(vm, uvma); 183} 184#endif 185 186int xe_vm_userptr_pin(struct xe_vm *vm) 187{ 188 struct xe_userptr_vma *uvma, *next; 189 int err = 0; 190 191 xe_assert(vm->xe, !xe_vm_in_fault_mode(vm)); 192 lockdep_assert_held_write(&vm->lock); 193 194 /* Collect invalidated userptrs */ 195 spin_lock(&vm->userptr.invalidated_lock); 196 xe_assert(vm->xe, list_empty(&vm->userptr.repin_list)); 197 list_for_each_entry_safe(uvma, next, &vm->userptr.invalidated, 198 userptr.invalidate_link) { 199 list_del_init(&uvma->userptr.invalidate_link); 200 list_add_tail(&uvma->userptr.repin_link, 201 &vm->userptr.repin_list); 202 } 203 spin_unlock(&vm->userptr.invalidated_lock); 204 205 /* Pin and move to bind list */ 206 list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list, 207 userptr.repin_link) { 208 err = xe_vma_userptr_pin_pages(uvma); 209 if (err == -EFAULT) { 210 list_del_init(&uvma->userptr.repin_link); 211 /* 212 * We might have already done the pin once already, but 213 * then had to retry before the re-bind happened, due 214 * some other condition in the caller, but in the 215 * meantime the userptr got dinged by the notifier such 216 * that we need to revalidate here, but this time we hit 217 * the EFAULT. In such a case make sure we remove 218 * ourselves from the rebind list to avoid going down in 219 * flames. 220 */ 221 if (!list_empty(&uvma->vma.combined_links.rebind)) 222 list_del_init(&uvma->vma.combined_links.rebind); 223 224 /* Wait for pending binds */ 225 xe_vm_lock(vm, false); 226 dma_resv_wait_timeout(xe_vm_resv(vm), 227 DMA_RESV_USAGE_BOOKKEEP, 228 false, MAX_SCHEDULE_TIMEOUT); 229 230 down_read(&vm->svm.gpusvm.notifier_lock); 231 err = xe_vm_invalidate_vma(&uvma->vma); 232 up_read(&vm->svm.gpusvm.notifier_lock); 233 xe_vm_unlock(vm); 234 if (err) 235 break; 236 } else { 237 if (err) 238 break; 239 240 list_del_init(&uvma->userptr.repin_link); 241 list_move_tail(&uvma->vma.combined_links.rebind, 242 &vm->rebind_list); 243 } 244 } 245 246 if (err) { 247 down_write(&vm->svm.gpusvm.notifier_lock); 248 spin_lock(&vm->userptr.invalidated_lock); 249 list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list, 250 userptr.repin_link) { 251 list_del_init(&uvma->userptr.repin_link); 252 list_move_tail(&uvma->userptr.invalidate_link, 253 &vm->userptr.invalidated); 254 } 255 spin_unlock(&vm->userptr.invalidated_lock); 256 up_write(&vm->svm.gpusvm.notifier_lock); 257 } 258 return err; 259} 260 261/** 262 * xe_vm_userptr_check_repin() - Check whether the VM might have userptrs 263 * that need repinning. 264 * @vm: The VM. 265 * 266 * This function does an advisory check for whether the VM has userptrs that 267 * need repinning. 268 * 269 * Return: 0 if there are no indications of userptrs needing repinning, 270 * -EAGAIN if there are. 271 */ 272int xe_vm_userptr_check_repin(struct xe_vm *vm) 273{ 274 return (list_empty_careful(&vm->userptr.repin_list) && 275 list_empty_careful(&vm->userptr.invalidated)) ? 0 : -EAGAIN; 276} 277 278int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start, 279 unsigned long range) 280{ 281 struct xe_userptr *userptr = &uvma->userptr; 282 int err; 283 284 INIT_LIST_HEAD(&userptr->invalidate_link); 285 INIT_LIST_HEAD(&userptr->repin_link); 286 287 err = mmu_interval_notifier_insert(&userptr->notifier, current->mm, 288 start, range, 289 &vma_userptr_notifier_ops); 290 if (err) 291 return err; 292 293 userptr->pages.notifier_seq = LONG_MAX; 294 295 return 0; 296} 297 298void xe_userptr_remove(struct xe_userptr_vma *uvma) 299{ 300 struct xe_vm *vm = xe_vma_vm(&uvma->vma); 301 struct xe_userptr *userptr = &uvma->userptr; 302 303 drm_gpusvm_free_pages(&vm->svm.gpusvm, &uvma->userptr.pages, 304 xe_vma_size(&uvma->vma) >> PAGE_SHIFT); 305 306 /* 307 * Since userptr pages are not pinned, we can't remove 308 * the notifier until we're sure the GPU is not accessing 309 * them anymore 310 */ 311 mmu_interval_notifier_remove(&userptr->notifier); 312} 313 314void xe_userptr_destroy(struct xe_userptr_vma *uvma) 315{ 316 struct xe_vm *vm = xe_vma_vm(&uvma->vma); 317 318 spin_lock(&vm->userptr.invalidated_lock); 319 xe_assert(vm->xe, list_empty(&uvma->userptr.repin_link)); 320 list_del(&uvma->userptr.invalidate_link); 321 spin_unlock(&vm->userptr.invalidated_lock); 322}