drm-vm-bind-locking.rst 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. .. SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  2. ===============
  3. VM_BIND locking
  4. ===============
  5. This document attempts to describe what's needed to get VM_BIND locking right,
  6. including the userptr mmu_notifier locking. It also discusses some
  7. optimizations to get rid of the looping through of all userptr mappings and
  8. external / shared object mappings that is needed in the simplest
  9. implementation. In addition, there is a section describing the VM_BIND locking
  10. required for implementing recoverable pagefaults.
  11. The DRM GPUVM set of helpers
  12. ============================
  13. There is a set of helpers for drivers implementing VM_BIND, and this
  14. set of helpers implements much, but not all of the locking described
  15. in this document. In particular, it is currently lacking a userptr
  16. implementation. This document does not intend to describe the DRM GPUVM
  17. implementation in detail, but it is covered in :ref:`its own
  18. documentation <drm_gpuvm>`. It is highly recommended for any driver
  19. implementing VM_BIND to use the DRM GPUVM helpers and to extend it if
  20. common functionality is missing.
  21. Nomenclature
  22. ============
  23. * ``gpu_vm``: Abstraction of a virtual GPU address space with
  24. meta-data. Typically one per client (DRM file-private), or one per
  25. execution context.
  26. * ``gpu_vma``: Abstraction of a GPU address range within a gpu_vm with
  27. associated meta-data. The backing storage of a gpu_vma can either be
  28. a GEM object or anonymous or page-cache pages mapped also into the CPU
  29. address space for the process.
  30. * ``gpu_vm_bo``: Abstracts the association of a GEM object and
  31. a VM. The GEM object maintains a list of gpu_vm_bos, where each gpu_vm_bo
  32. maintains a list of gpu_vmas.
  33. * ``userptr gpu_vma or just userptr``: A gpu_vma, whose backing store
  34. is anonymous or page-cache pages as described above.
  35. * ``revalidating``: Revalidating a gpu_vma means making the latest version
  36. of the backing store resident and making sure the gpu_vma's
  37. page-table entries point to that backing store.
  38. * ``dma_fence``: A struct dma_fence that is similar to a struct completion
  39. and which tracks GPU activity. When the GPU activity is finished,
  40. the dma_fence signals. Please refer to the ``DMA Fences`` section of
  41. the :doc:`dma-buf doc </driver-api/dma-buf>`.
  42. * ``dma_resv``: A struct dma_resv (a.k.a reservation object) that is used
  43. to track GPU activity in the form of multiple dma_fences on a
  44. gpu_vm or a GEM object. The dma_resv contains an array / list
  45. of dma_fences and a lock that needs to be held when adding
  46. additional dma_fences to the dma_resv. The lock is of a type that
  47. allows deadlock-safe locking of multiple dma_resvs in arbitrary
  48. order. Please refer to the ``Reservation Objects`` section of the
  49. :doc:`dma-buf doc </driver-api/dma-buf>`.
  50. * ``exec function``: An exec function is a function that revalidates all
  51. affected gpu_vmas, submits a GPU command batch and registers the
  52. dma_fence representing the GPU command's activity with all affected
  53. dma_resvs. For completeness, although not covered by this document,
  54. it's worth mentioning that an exec function may also be the
  55. revalidation worker that is used by some drivers in compute /
  56. long-running mode.
  57. * ``local object``: A GEM object which is only mapped within a
  58. single VM. Local GEM objects share the gpu_vm's dma_resv.
  59. * ``external object``: a.k.a shared object: A GEM object which may be shared
  60. by multiple gpu_vms and whose backing storage may be shared with
  61. other drivers.
  62. Locks and locking order
  63. =======================
  64. One of the benefits of VM_BIND is that local GEM objects share the gpu_vm's
  65. dma_resv object and hence the dma_resv lock. So, even with a huge
  66. number of local GEM objects, only one lock is needed to make the exec
  67. sequence atomic.
  68. The following locks and locking orders are used:
  69. * The ``gpu_vm->lock`` (optionally an rwsem). Protects the gpu_vm's
  70. data structure keeping track of gpu_vmas. It can also protect the
  71. gpu_vm's list of userptr gpu_vmas. With a CPU mm analogy this would
  72. correspond to the mmap_lock. An rwsem allows several readers to walk
  73. the VM tree concurrently, but the benefit of that concurrency most
  74. likely varies from driver to driver.
  75. * The ``userptr_seqlock``. This lock is taken in read mode for each
  76. userptr gpu_vma on the gpu_vm's userptr list, and in write mode during mmu
  77. notifier invalidation. This is not a real seqlock but described in
  78. ``mm/mmu_notifier.c`` as a "Collision-retry read-side/write-side
  79. 'lock' a lot like a seqcount. However this allows multiple
  80. write-sides to hold it at once...". The read side critical section
  81. is enclosed by ``mmu_interval_read_begin() /
  82. mmu_interval_read_retry()`` with ``mmu_interval_read_begin()``
  83. sleeping if the write side is held.
  84. The write side is held by the core mm while calling mmu interval
  85. invalidation notifiers.
  86. * The ``gpu_vm->resv`` lock. Protects the gpu_vm's list of gpu_vmas needing
  87. rebinding, as well as the residency state of all the gpu_vm's local
  88. GEM objects.
  89. Furthermore, it typically protects the gpu_vm's list of evicted and
  90. external GEM objects.
  91. * The ``gpu_vm->userptr_notifier_lock``. This is an rwsem that is
  92. taken in read mode during exec and write mode during a mmu notifier
  93. invalidation. The userptr notifier lock is per gpu_vm.
  94. * The ``gem_object->gpuva_lock`` This lock protects the GEM object's
  95. list of gpu_vm_bos. This is usually the same lock as the GEM
  96. object's dma_resv, but some drivers protects this list differently,
  97. see below.
  98. * The ``gpu_vm list spinlocks``. With some implementations they are needed
  99. to be able to update the gpu_vm evicted- and external object
  100. list. For those implementations, the spinlocks are grabbed when the
  101. lists are manipulated. However, to avoid locking order violations
  102. with the dma_resv locks, a special scheme is needed when iterating
  103. over the lists.
  104. .. _gpu_vma lifetime:
  105. Protection and lifetime of gpu_vm_bos and gpu_vmas
  106. ==================================================
  107. The GEM object's list of gpu_vm_bos, and the gpu_vm_bo's list of gpu_vmas
  108. is protected by the ``gem_object->gpuva_lock``, which is typically the
  109. same as the GEM object's dma_resv, but if the driver
  110. needs to access these lists from within a dma_fence signalling
  111. critical section, it can instead choose to protect it with a
  112. separate lock, which can be locked from within the dma_fence signalling
  113. critical section. Such drivers then need to pay additional attention
  114. to what locks need to be taken from within the loop when iterating
  115. over the gpu_vm_bo and gpu_vma lists to avoid locking-order violations.
  116. The DRM GPUVM set of helpers provide lockdep asserts that this lock is
  117. held in relevant situations and also provides a means of making itself
  118. aware of which lock is actually used: :c:func:`drm_gem_gpuva_set_lock`.
  119. Each gpu_vm_bo holds a reference counted pointer to the underlying GEM
  120. object, and each gpu_vma holds a reference counted pointer to the
  121. gpu_vm_bo. When iterating over the GEM object's list of gpu_vm_bos and
  122. over the gpu_vm_bo's list of gpu_vmas, the ``gem_object->gpuva_lock`` must
  123. not be dropped, otherwise, gpu_vmas attached to a gpu_vm_bo may
  124. disappear without notice since those are not reference-counted. A
  125. driver may implement its own scheme to allow this at the expense of
  126. additional complexity, but this is outside the scope of this document.
  127. In the DRM GPUVM implementation, each gpu_vm_bo and each gpu_vma
  128. holds a reference count on the gpu_vm itself. Due to this, and to avoid circular
  129. reference counting, cleanup of the gpu_vm's gpu_vmas must not be done from the
  130. gpu_vm's destructor. Drivers typically implements a gpu_vm close
  131. function for this cleanup. The gpu_vm close function will abort gpu
  132. execution using this VM, unmap all gpu_vmas and release page-table memory.
  133. Revalidation and eviction of local objects
  134. ==========================================
  135. Note that in all the code examples given below we use simplified
  136. pseudo-code. In particular, the dma_resv deadlock avoidance algorithm
  137. as well as reserving memory for dma_resv fences is left out.
  138. Revalidation
  139. ____________
  140. With VM_BIND, all local objects need to be resident when the gpu is
  141. executing using the gpu_vm, and the objects need to have valid
  142. gpu_vmas set up pointing to them. Typically, each gpu command buffer
  143. submission is therefore preceded with a re-validation section:
  144. .. code-block:: C
  145. dma_resv_lock(gpu_vm->resv);
  146. // Validation section starts here.
  147. for_each_gpu_vm_bo_on_evict_list(&gpu_vm->evict_list, &gpu_vm_bo) {
  148. validate_gem_bo(&gpu_vm_bo->gem_bo);
  149. // The following list iteration needs the Gem object's
  150. // dma_resv to be held (it protects the gpu_vm_bo's list of
  151. // gpu_vmas, but since local gem objects share the gpu_vm's
  152. // dma_resv, it is already held at this point.
  153. for_each_gpu_vma_of_gpu_vm_bo(&gpu_vm_bo, &gpu_vma)
  154. move_gpu_vma_to_rebind_list(&gpu_vma, &gpu_vm->rebind_list);
  155. }
  156. for_each_gpu_vma_on_rebind_list(&gpu vm->rebind_list, &gpu_vma) {
  157. rebind_gpu_vma(&gpu_vma);
  158. remove_gpu_vma_from_rebind_list(&gpu_vma);
  159. }
  160. // Validation section ends here, and job submission starts.
  161. add_dependencies(&gpu_job, &gpu_vm->resv);
  162. job_dma_fence = gpu_submit(&gpu_job));
  163. add_dma_fence(job_dma_fence, &gpu_vm->resv);
  164. dma_resv_unlock(gpu_vm->resv);
  165. The reason for having a separate gpu_vm rebind list is that there
  166. might be userptr gpu_vmas that are not mapping a buffer object that
  167. also need rebinding.
  168. Eviction
  169. ________
  170. Eviction of one of these local objects will then look similar to the
  171. following:
  172. .. code-block:: C
  173. obj = get_object_from_lru();
  174. dma_resv_lock(obj->resv);
  175. for_each_gpu_vm_bo_of_obj(obj, &gpu_vm_bo);
  176. add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list);
  177. add_dependencies(&eviction_job, &obj->resv);
  178. job_dma_fence = gpu_submit(&eviction_job);
  179. add_dma_fence(&obj->resv, job_dma_fence);
  180. dma_resv_unlock(&obj->resv);
  181. put_object(obj);
  182. Note that since the object is local to the gpu_vm, it will share the gpu_vm's
  183. dma_resv lock such that ``obj->resv == gpu_vm->resv``.
  184. The gpu_vm_bos marked for eviction are put on the gpu_vm's evict list,
  185. which is protected by ``gpu_vm->resv``. During eviction all local
  186. objects have their dma_resv locked and, due to the above equality, also
  187. the gpu_vm's dma_resv protecting the gpu_vm's evict list is locked.
  188. With VM_BIND, gpu_vmas don't need to be unbound before eviction,
  189. since the driver must ensure that the eviction blit or copy will wait
  190. for GPU idle or depend on all previous GPU activity. Furthermore, any
  191. subsequent attempt by the GPU to access freed memory through the
  192. gpu_vma will be preceded by a new exec function, with a revalidation
  193. section which will make sure all gpu_vmas are rebound. The eviction
  194. code holding the object's dma_resv while revalidating will ensure a
  195. new exec function may not race with the eviction.
  196. A driver can be implemented in such a way that, on each exec function,
  197. only a subset of vmas are selected for rebind. In this case, all vmas that are
  198. *not* selected for rebind must be unbound before the exec
  199. function workload is submitted.
  200. Locking with external buffer objects
  201. ====================================
  202. Since external buffer objects may be shared by multiple gpu_vm's they
  203. can't share their reservation object with a single gpu_vm. Instead
  204. they need to have a reservation object of their own. The external
  205. objects bound to a gpu_vm using one or many gpu_vmas are therefore put on a
  206. per-gpu_vm list which is protected by the gpu_vm's dma_resv lock or
  207. one of the :ref:`gpu_vm list spinlocks <Spinlock iteration>`. Once
  208. the gpu_vm's reservation object is locked, it is safe to traverse the
  209. external object list and lock the dma_resvs of all external
  210. objects. However, if instead a list spinlock is used, a more elaborate
  211. iteration scheme needs to be used.
  212. At eviction time, the gpu_vm_bos of *all* the gpu_vms an external
  213. object is bound to need to be put on their gpu_vm's evict list.
  214. However, when evicting an external object, the dma_resvs of the
  215. gpu_vms the object is bound to are typically not held. Only
  216. the object's private dma_resv can be guaranteed to be held. If there
  217. is a ww_acquire context at hand at eviction time we could grab those
  218. dma_resvs but that could cause expensive ww_mutex rollbacks. A simple
  219. option is to just mark the gpu_vm_bos of the evicted gem object with
  220. an ``evicted`` bool that is inspected before the next time the
  221. corresponding gpu_vm evicted list needs to be traversed. For example, when
  222. traversing the list of external objects and locking them. At that time,
  223. both the gpu_vm's dma_resv and the object's dma_resv is held, and the
  224. gpu_vm_bo marked evicted, can then be added to the gpu_vm's list of
  225. evicted gpu_vm_bos. The ``evicted`` bool is formally protected by the
  226. object's dma_resv.
  227. The exec function becomes
  228. .. code-block:: C
  229. dma_resv_lock(gpu_vm->resv);
  230. // External object list is protected by the gpu_vm->resv lock.
  231. for_each_gpu_vm_bo_on_extobj_list(gpu_vm, &gpu_vm_bo) {
  232. dma_resv_lock(gpu_vm_bo.gem_obj->resv);
  233. if (gpu_vm_bo_marked_evicted(&gpu_vm_bo))
  234. add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list);
  235. }
  236. for_each_gpu_vm_bo_on_evict_list(&gpu_vm->evict_list, &gpu_vm_bo) {
  237. validate_gem_bo(&gpu_vm_bo->gem_bo);
  238. for_each_gpu_vma_of_gpu_vm_bo(&gpu_vm_bo, &gpu_vma)
  239. move_gpu_vma_to_rebind_list(&gpu_vma, &gpu_vm->rebind_list);
  240. }
  241. for_each_gpu_vma_on_rebind_list(&gpu vm->rebind_list, &gpu_vma) {
  242. rebind_gpu_vma(&gpu_vma);
  243. remove_gpu_vma_from_rebind_list(&gpu_vma);
  244. }
  245. add_dependencies(&gpu_job, &gpu_vm->resv);
  246. job_dma_fence = gpu_submit(&gpu_job));
  247. add_dma_fence(job_dma_fence, &gpu_vm->resv);
  248. for_each_external_obj(gpu_vm, &obj)
  249. add_dma_fence(job_dma_fence, &obj->resv);
  250. dma_resv_unlock_all_resv_locks();
  251. And the corresponding shared-object aware eviction would look like:
  252. .. code-block:: C
  253. obj = get_object_from_lru();
  254. dma_resv_lock(obj->resv);
  255. for_each_gpu_vm_bo_of_obj(obj, &gpu_vm_bo)
  256. if (object_is_vm_local(obj))
  257. add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list);
  258. else
  259. mark_gpu_vm_bo_evicted(&gpu_vm_bo);
  260. add_dependencies(&eviction_job, &obj->resv);
  261. job_dma_fence = gpu_submit(&eviction_job);
  262. add_dma_fence(&obj->resv, job_dma_fence);
  263. dma_resv_unlock(&obj->resv);
  264. put_object(obj);
  265. .. _Spinlock iteration:
  266. Accessing the gpu_vm's lists without the dma_resv lock held
  267. ===========================================================
  268. Some drivers will hold the gpu_vm's dma_resv lock when accessing the
  269. gpu_vm's evict list and external objects lists. However, there are
  270. drivers that need to access these lists without the dma_resv lock
  271. held, for example due to asynchronous state updates from within the
  272. dma_fence signalling critical path. In such cases, a spinlock can be
  273. used to protect manipulation of the lists. However, since higher level
  274. sleeping locks need to be taken for each list item while iterating
  275. over the lists, the items already iterated over need to be
  276. temporarily moved to a private list and the spinlock released
  277. while processing each item:
  278. .. code block:: C
  279. struct list_head still_in_list;
  280. INIT_LIST_HEAD(&still_in_list);
  281. spin_lock(&gpu_vm->list_lock);
  282. do {
  283. struct list_head *entry = list_first_entry_or_null(&gpu_vm->list, head);
  284. if (!entry)
  285. break;
  286. list_move_tail(&entry->head, &still_in_list);
  287. list_entry_get_unless_zero(entry);
  288. spin_unlock(&gpu_vm->list_lock);
  289. process(entry);
  290. spin_lock(&gpu_vm->list_lock);
  291. list_entry_put(entry);
  292. } while (true);
  293. list_splice_tail(&still_in_list, &gpu_vm->list);
  294. spin_unlock(&gpu_vm->list_lock);
  295. Due to the additional locking and atomic operations, drivers that *can*
  296. avoid accessing the gpu_vm's list outside of the dma_resv lock
  297. might want to avoid also this iteration scheme. Particularly, if the
  298. driver anticipates a large number of list items. For lists where the
  299. anticipated number of list items is small, where list iteration doesn't
  300. happen very often or if there is a significant additional cost
  301. associated with each iteration, the atomic operation overhead
  302. associated with this type of iteration is, most likely, negligible. Note that
  303. if this scheme is used, it is necessary to make sure this list
  304. iteration is protected by an outer level lock or semaphore, since list
  305. items are temporarily pulled off the list while iterating, and it is
  306. also worth mentioning that the local list ``still_in_list`` should
  307. also be considered protected by the ``gpu_vm->list_lock``, and it is
  308. thus possible that items can be removed also from the local list
  309. concurrently with list iteration.
  310. Please refer to the :ref:`DRM GPUVM locking section
  311. <drm_gpuvm_locking>` and its internal
  312. :c:func:`get_next_vm_bo_from_list` function.
  313. userptr gpu_vmas
  314. ================
  315. A userptr gpu_vma is a gpu_vma that, instead of mapping a buffer object to a
  316. GPU virtual address range, directly maps a CPU mm range of anonymous-
  317. or file page-cache pages.
  318. A very simple approach would be to just pin the pages using
  319. pin_user_pages() at bind time and unpin them at unbind time, but this
  320. creates a Denial-Of-Service vector since a single user-space process
  321. would be able to pin down all of system memory, which is not
  322. desirable. (For special use-cases and assuming proper accounting pinning might
  323. still be a desirable feature, though). What we need to do in the
  324. general case is to obtain a reference to the desired pages, make sure
  325. we are notified using a MMU notifier just before the CPU mm unmaps the
  326. pages, dirty them if they are not mapped read-only to the GPU, and
  327. then drop the reference.
  328. When we are notified by the MMU notifier that CPU mm is about to drop the
  329. pages, we need to stop GPU access to the pages by waiting for VM idle
  330. in the MMU notifier and make sure that before the next time the GPU
  331. tries to access whatever is now present in the CPU mm range, we unmap
  332. the old pages from the GPU page tables and repeat the process of
  333. obtaining new page references. (See the :ref:`notifier example
  334. <Invalidation example>` below). Note that when the core mm decides to
  335. laundry pages, we get such an unmap MMU notification and can mark the
  336. pages dirty again before the next GPU access. We also get similar MMU
  337. notifications for NUMA accounting which the GPU driver doesn't really
  338. need to care about, but so far it has proven difficult to exclude
  339. certain notifications.
  340. Using a MMU notifier for device DMA (and other methods) is described in
  341. :ref:`the pin_user_pages() documentation <mmu-notifier-registration-case>`.
  342. Now, the method of obtaining struct page references using
  343. get_user_pages() unfortunately can't be used under a dma_resv lock
  344. since that would violate the locking order of the dma_resv lock vs the
  345. mmap_lock that is grabbed when resolving a CPU pagefault. This means
  346. the gpu_vm's list of userptr gpu_vmas needs to be protected by an
  347. outer lock, which in our example below is the ``gpu_vm->lock``.
  348. The MMU interval seqlock for a userptr gpu_vma is used in the following
  349. way:
  350. .. code-block:: C
  351. // Exclusive locking mode here is strictly needed only if there are
  352. // invalidated userptr gpu_vmas present, to avoid concurrent userptr
  353. // revalidations of the same userptr gpu_vma.
  354. down_write(&gpu_vm->lock);
  355. retry:
  356. // Note: mmu_interval_read_begin() blocks until there is no
  357. // invalidation notifier running anymore.
  358. seq = mmu_interval_read_begin(&gpu_vma->userptr_interval);
  359. if (seq != gpu_vma->saved_seq) {
  360. obtain_new_page_pointers(&gpu_vma);
  361. dma_resv_lock(&gpu_vm->resv);
  362. add_gpu_vma_to_revalidate_list(&gpu_vma, &gpu_vm);
  363. dma_resv_unlock(&gpu_vm->resv);
  364. gpu_vma->saved_seq = seq;
  365. }
  366. // The usual revalidation goes here.
  367. // Final userptr sequence validation may not happen before the
  368. // submission dma_fence is added to the gpu_vm's resv, from the POW
  369. // of the MMU invalidation notifier. Hence the
  370. // userptr_notifier_lock that will make them appear atomic.
  371. add_dependencies(&gpu_job, &gpu_vm->resv);
  372. down_read(&gpu_vm->userptr_notifier_lock);
  373. if (mmu_interval_read_retry(&gpu_vma->userptr_interval, gpu_vma->saved_seq)) {
  374. up_read(&gpu_vm->userptr_notifier_lock);
  375. goto retry;
  376. }
  377. job_dma_fence = gpu_submit(&gpu_job));
  378. add_dma_fence(job_dma_fence, &gpu_vm->resv);
  379. for_each_external_obj(gpu_vm, &obj)
  380. add_dma_fence(job_dma_fence, &obj->resv);
  381. dma_resv_unlock_all_resv_locks();
  382. up_read(&gpu_vm->userptr_notifier_lock);
  383. up_write(&gpu_vm->lock);
  384. The code between ``mmu_interval_read_begin()`` and the
  385. ``mmu_interval_read_retry()`` marks the read side critical section of
  386. what we call the ``userptr_seqlock``. In reality, the gpu_vm's userptr
  387. gpu_vma list is looped through, and the check is done for *all* of its
  388. userptr gpu_vmas, although we only show a single one here.
  389. The userptr gpu_vma MMU invalidation notifier might be called from
  390. reclaim context and, again, to avoid locking order violations, we can't
  391. take any dma_resv lock nor the gpu_vm->lock from within it.
  392. .. _Invalidation example:
  393. .. code-block:: C
  394. bool gpu_vma_userptr_invalidate(userptr_interval, cur_seq)
  395. {
  396. // Make sure the exec function either sees the new sequence
  397. // and backs off or we wait for the dma-fence:
  398. down_write(&gpu_vm->userptr_notifier_lock);
  399. mmu_interval_set_seq(userptr_interval, cur_seq);
  400. up_write(&gpu_vm->userptr_notifier_lock);
  401. // At this point, the exec function can't succeed in
  402. // submitting a new job, because cur_seq is an invalid
  403. // sequence number and will always cause a retry. When all
  404. // invalidation callbacks, the mmu notifier core will flip
  405. // the sequence number to a valid one. However we need to
  406. // stop gpu access to the old pages here.
  407. dma_resv_wait_timeout(&gpu_vm->resv, DMA_RESV_USAGE_BOOKKEEP,
  408. false, MAX_SCHEDULE_TIMEOUT);
  409. return true;
  410. }
  411. When this invalidation notifier returns, the GPU can no longer be
  412. accessing the old pages of the userptr gpu_vma and needs to redo the
  413. page-binding before a new GPU submission can succeed.
  414. Efficient userptr gpu_vma exec_function iteration
  415. _________________________________________________
  416. If the gpu_vm's list of userptr gpu_vmas becomes large, it's
  417. inefficient to iterate through the complete lists of userptrs on each
  418. exec function to check whether each userptr gpu_vma's saved
  419. sequence number is stale. A solution to this is to put all
  420. *invalidated* userptr gpu_vmas on a separate gpu_vm list and
  421. only check the gpu_vmas present on this list on each exec
  422. function. This list will then lend itself very-well to the spinlock
  423. locking scheme that is
  424. :ref:`described in the spinlock iteration section <Spinlock iteration>`, since
  425. in the mmu notifier, where we add the invalidated gpu_vmas to the
  426. list, it's not possible to take any outer locks like the
  427. ``gpu_vm->lock`` or the ``gpu_vm->resv`` lock. Note that the
  428. ``gpu_vm->lock`` still needs to be taken while iterating to ensure the list is
  429. complete, as also mentioned in that section.
  430. If using an invalidated userptr list like this, the retry check in the
  431. exec function trivially becomes a check for invalidated list empty.
  432. Locking at bind and unbind time
  433. ===============================
  434. At bind time, assuming a GEM object backed gpu_vma, each
  435. gpu_vma needs to be associated with a gpu_vm_bo and that
  436. gpu_vm_bo in turn needs to be added to the GEM object's
  437. gpu_vm_bo list, and possibly to the gpu_vm's external object
  438. list. This is referred to as *linking* the gpu_vma, and typically
  439. requires that the ``gpu_vm->lock`` and the ``gem_object->gpuva_lock``
  440. are held. When unlinking a gpu_vma the same locks should be held,
  441. and that ensures that when iterating over ``gpu_vmas`, either under
  442. the ``gpu_vm->resv`` or the GEM object's dma_resv, that the gpu_vmas
  443. stay alive as long as the lock under which we iterate is not released. For
  444. userptr gpu_vmas it's similarly required that during vma destroy, the
  445. outer ``gpu_vm->lock`` is held, since otherwise when iterating over
  446. the invalidated userptr list as described in the previous section,
  447. there is nothing keeping those userptr gpu_vmas alive.
  448. Locking for recoverable page-fault page-table updates
  449. =====================================================
  450. There are two important things we need to ensure with locking for
  451. recoverable page-faults:
  452. * At the time we return pages back to the system / allocator for
  453. reuse, there should be no remaining GPU mappings and any GPU TLB
  454. must have been flushed.
  455. * The unmapping and mapping of a gpu_vma must not race.
  456. Since the unmapping (or zapping) of GPU ptes is typically taking place
  457. where it is hard or even impossible to take any outer level locks we
  458. must either introduce a new lock that is held at both mapping and
  459. unmapping time, or look at the locks we do hold at unmapping time and
  460. make sure that they are held also at mapping time. For userptr
  461. gpu_vmas, the ``userptr_seqlock`` is held in write mode in the mmu
  462. invalidation notifier where zapping happens. Hence, if the
  463. ``userptr_seqlock`` as well as the ``gpu_vm->userptr_notifier_lock``
  464. is held in read mode during mapping, it will not race with the
  465. zapping. For GEM object backed gpu_vmas, zapping will take place under
  466. the GEM object's dma_resv and ensuring that the dma_resv is held also
  467. when populating the page-tables for any gpu_vma pointing to the GEM
  468. object, will similarly ensure we are race-free.
  469. If any part of the mapping is performed asynchronously
  470. under a dma-fence with these locks released, the zapping will need to
  471. wait for that dma-fence to signal under the relevant lock before
  472. starting to modify the page-table.
  473. Since modifying the
  474. page-table structure in a way that frees up page-table memory
  475. might also require outer level locks, the zapping of GPU ptes
  476. typically focuses only on zeroing page-table or page-directory entries
  477. and flushing TLB, whereas freeing of page-table memory is deferred to
  478. unbind or rebind time.