€•�Œsphinx.addnodes”Œdocument”“”)�”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)�”}”(hhh]”(hŒ pending_xref”“”)�”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…”�”}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ"/translations/zh_CN/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)�”}”(hhh]”hŒChinese (Traditional)”…”�”}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ"/translations/zh_TW/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒItalian”…”�”}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ"/translations/it_IT/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒJapanese”…”�”}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ"/translations/ja_JP/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒKorean”…”�”}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ"/translations/ko_KR/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒPortuguese (Brazilian)”…”�”}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ"/translations/pt_BR/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒSpanish”…”�”}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ"/translations/sp_SP/gpu/rfc/gpusvm”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)�”}”(hŒ*SPDX-License-Identifier: (GPL-2.0+ OR MIT)”h]”hŒ*SPDX-License-Identifier: (GPL-2.0+ OR MIT)”…”�”}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³ŒNo looking at mm/vma structs or relying on those being locked.”h]”j!)�”}”(hjh]”hŒ>No looking at mm/vma structs or relying on those being locked.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjÑubhô)�”}”(hŒ†The rationale for the above two points is that CPU virtual addresses can change at any moment, while the physical pages remain stable.”h]”j!)�”}”(hŒ†The rationale for the above two points is that CPU virtual addresses can change at any moment, while the physical pages remain stable.”h]”hŒ†The rationale for the above two points is that CPU virtual addresses can change at any moment, while the physical pages remain stable.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjÑubhô)�”}”(hŒŠGPU page table invalidation, which requires a GPU virtual address, is handled via the notifier that has access to the GPU virtual address.”h]”j!)�”}”(hŒŠGPU page table invalidation, which requires a GPU virtual address, is handled via the notifier that has access to the GPU virtual address.”h]”hŒŠGPU page table invalidation, which requires a GPU virtual address, is handled via the notifier that has access to the GPU virtual address.”…”�”}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K hj3ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjÑubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´KhjÎubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¼ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´K hj¹ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjµubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhhðh²hh³Nh´Nubhô)�”}”(hX•GPU fault side * mmap_read only used around core MM functions which require this lock and should strive to take mmap_read lock only in GPU SVM layer. * Big retry loop to handle all races with the mmu notifier under the gpu pagetable locks/mmu notifier range lock/whatever we end up calling those. * Races (especially against concurrent eviction or migrate_to_ram) should not be handled on the fault side by trying to hold locks; rather, they should be handled using retry loops. One possible exception is holding a BO's dma-resv lock during the initial migration to VRAM, as this is a well-defined lock that can be taken underneath the mmap_read lock. * One possible issue with the above approach is if a driver has a strict migration policy requiring GPU access to occur in GPU memory. Concurrent CPU access could cause a livelock due to endless retries. While no current user (Xe) of GPU SVM has such a policy, it is likely to be added in the future. Ideally, this should be resolved on the core-MM side rather than through a driver-side lock.”h]”hú)�”}”(hhh]”hÿ)�”}”(hX/GPU fault side * mmap_read only used around core MM functions which require this lock and should strive to take mmap_read lock only in GPU SVM layer. * Big retry loop to handle all races with the mmu notifier under the gpu pagetable locks/mmu notifier range lock/whatever we end up calling those. * Races (especially against concurrent eviction or migrate_to_ram) should not be handled on the fault side by trying to hold locks; rather, they should be handled using retry loops. One possible exception is holding a BO's dma-resv lock during the initial migration to VRAM, as this is a well-defined lock that can be taken underneath the mmap_read lock. * One possible issue with the above approach is if a driver has a strict migration policy requiring GPU access to occur in GPU memory. Concurrent CPU access could cause a livelock due to endless retries. While no current user (Xe) of GPU SVM has such a policy, it is likely to be added in the future. Ideally, this should be resolved on the core-MM side rather than through a driver-side lock.”h]”(j)�”}”(hŒGPU fault side”h]”hŒGPU fault side”…”�”}”(hjth²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´K2hjpubj)�”}”(hhh]”hï)�”}”(hhh]”(hô)�”}”(hŒ„mmap_read only used around core MM functions which require this lock and should strive to take mmap_read lock only in GPU SVM layer.”h]”j!)�”}”(hŒ„mmap_read only used around core MM functions which require this lock and should strive to take mmap_read lock only in GPU SVM layer.”h]”hŒ„mmap_read only used around core MM functions which require this lock and should strive to take mmap_read lock only in GPU SVM layer.”…”�”}”(hjŒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K#hjˆubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj…ubhô)�”}”(hŒ�Big retry loop to handle all races with the mmu notifier under the gpu pagetable locks/mmu notifier range lock/whatever we end up calling those.”h]”j!)�”}”(hŒ�Big retry loop to handle all races with the mmu notifier under the gpu pagetable locks/mmu notifier range lock/whatever we end up calling those.”h]”hŒ�Big retry loop to handle all races with the mmu notifier under the gpu pagetable locks/mmu notifier range lock/whatever we end up calling those.”…”�”}”(hj¤h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K%hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj…ubhô)�”}”(hX`Races (especially against concurrent eviction or migrate_to_ram) should not be handled on the fault side by trying to hold locks; rather, they should be handled using retry loops. One possible exception is holding a BO's dma-resv lock during the initial migration to VRAM, as this is a well-defined lock that can be taken underneath the mmap_read lock.”h]”j!)�”}”(hX`Races (especially against concurrent eviction or migrate_to_ram) should not be handled on the fault side by trying to hold locks; rather, they should be handled using retry loops. One possible exception is holding a BO's dma-resv lock during the initial migration to VRAM, as this is a well-defined lock that can be taken underneath the mmap_read lock.”h]”hXbRaces (especially against concurrent eviction or migrate_to_ram) should not be handled on the fault side by trying to hold locks; rather, they should be handled using retry loops. One possible exception is holding a BO’s dma-resv lock during the initial migration to VRAM, as this is a well-defined lock that can be taken underneath the mmap_read lock.”…”�”}”(hj¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K(hj¸ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj…ubhô)�”}”(hX‡One possible issue with the above approach is if a driver has a strict migration policy requiring GPU access to occur in GPU memory. Concurrent CPU access could cause a livelock due to endless retries. While no current user (Xe) of GPU SVM has such a policy, it is likely to be added in the future. Ideally, this should be resolved on the core-MM side rather than through a driver-side lock.”h]”j!)�”}”(hX‡One possible issue with the above approach is if a driver has a strict migration policy requiring GPU access to occur in GPU memory. Concurrent CPU access could cause a livelock due to endless retries. While no current user (Xe) of GPU SVM has such a policy, it is likely to be added in the future. Ideally, this should be resolved on the core-MM side rather than through a driver-side lock.”h]”hX‡One possible issue with the above approach is if a driver has a strict migration policy requiring GPU access to occur in GPU memory. Concurrent CPU access could cause a livelock due to endless retries. While no current user (Xe) of GPU SVM has such a policy, it is likely to be added in the future. Ideally, this should be resolved on the core-MM side rather than through a driver-side lock.”…”�”}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K.hjÐubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj…ubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´K#hj‚ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjpubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´K2hjmubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjiubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhhðh²hh³Nh´Nubhô)�”}”(hX0Physical memory to virtual backpointer * This does not work, as no pointers from physical memory to virtual memory should exist. mremap() is an example of the core MM updating the virtual address without notifying the driver of address change rather the driver only receiving the invalidation notifier. * The physical memory backpointer (page->zone_device_data) should remain stable from allocation to page free. Safely updating this against a concurrent user would be very difficult unless the page is free.”h]”hú)�”}”(hhh]”hÿ)�”}”(hXPhysical memory to virtual backpointer * This does not work, as no pointers from physical memory to virtual memory should exist. mremap() is an example of the core MM updating the virtual address without notifying the driver of address change rather the driver only receiving the invalidation notifier. * The physical memory backpointer (page->zone_device_data) should remain stable from allocation to page free. Safely updating this against a concurrent user would be very difficult unless the page is free.”h]”(j)�”}”(hŒ&Physical memory to virtual backpointer”h]”hŒ&Physical memory to virtual backpointer”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´K:hj ubj)�”}”(hhh]”hï)�”}”(hhh]”(hô)�”}”(hXThis does not work, as no pointers from physical memory to virtual memory should exist. mremap() is an example of the core MM updating the virtual address without notifying the driver of address change rather the driver only receiving the invalidation notifier.”h]”j!)�”}”(hXThis does not work, as no pointers from physical memory to virtual memory should exist. mremap() is an example of the core MM updating the virtual address without notifying the driver of address change rather the driver only receiving the invalidation notifier.”h]”hXThis does not work, as no pointers from physical memory to virtual memory should exist. mremap() is an example of the core MM updating the virtual address without notifying the driver of address change rather the driver only receiving the invalidation notifier.”…”�”}”(hj)h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K5hj%ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj"ubhô)�”}”(hŒËThe physical memory backpointer (page->zone_device_data) should remain stable from allocation to page free. Safely updating this against a concurrent user would be very difficult unless the page is free.”h]”j!)�”}”(hŒËThe physical memory backpointer (page->zone_device_data) should remain stable from allocation to page free. Safely updating this against a concurrent user would be very difficult unless the page is free.”h]”hŒËThe physical memory backpointer (page->zone_device_data) should remain stable from allocation to page free. Safely updating this against a concurrent user would be very difficult unless the page is free.”…”�”}”(hjAh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K9hj=ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj"ubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´K5hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´K:hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhhðh²hh³Nh´Nubhô)�”}”(hXKGPU pagetable locking * Notifier lock only protects range tree, pages valid state for a range (rather than seqno due to wider notifiers), pagetable entries, and mmu notifier seqno tracking, it is not a global lock to protect against races. * All races handled with big retry as mentioned above. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hX-GPU pagetable locking * Notifier lock only protects range tree, pages valid state for a range (rather than seqno due to wider notifiers), pagetable entries, and mmu notifier seqno tracking, it is not a global lock to protect against races. * All races handled with big retry as mentioned above. ”h]”(j)�”}”(hŒGPU pagetable locking”h]”hŒGPU pagetable locking”…”�”}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´KAhjzubj)�”}”(hhh]”hï)�”}”(hhh]”(hô)�”}”(hŒ×Notifier lock only protects range tree, pages valid state for a range (rather than seqno due to wider notifiers), pagetable entries, and mmu notifier seqno tracking, it is not a global lock to protect against races.”h]”j!)�”}”(hŒ×Notifier lock only protects range tree, pages valid state for a range (rather than seqno due to wider notifiers), pagetable entries, and mmu notifier seqno tracking, it is not a global lock to protect against races.”h]”hŒ×Notifier lock only protects range tree, pages valid state for a range (rather than seqno due to wider notifiers), pagetable entries, and mmu notifier seqno tracking, it is not a global lock to protect against races.”…”�”}”(hj–h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K=hj’ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj�ubhô)�”}”(hŒ5All races handled with big retry as mentioned above. ”h]”j!)�”}”(hŒ4All races handled with big retry as mentioned above.”h]”hŒ4All races handled with big retry as mentioned above.”…”�”}”(hj®h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KAhjªubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj�ubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´K=hjŒubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjzubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´KAhjwubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjsubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhhðh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´K hhÝh²hubeh}”(h]”Œagreed-upon-design-principles”ah ]”h"]”Œagreed upon design principles”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒOverview of baseline design”h]”hŒOverview of baseline design”…”�”}”(hjñh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjîh²hh³hÇh´KDubj!)�”}”(hXlGPU Shared Virtual Memory (GPU SVM) layer for the Direct Rendering Manager (DRM) is a component of the DRM framework designed to manage shared virtual memory between the CPU and GPU. It enables efficient data exchange and processing for GPU-accelerated applications by allowing memory sharing and synchronization between the CPU's and GPU's virtual address spaces.”h]”hXpGPU Shared Virtual Memory (GPU SVM) layer for the Direct Rendering Manager (DRM) is a component of the DRM framework designed to manage shared virtual memory between the CPU and GPU. It enables efficient data exchange and processing for GPU-accelerated applications by allowing memory sharing and synchronization between the CPU’s and GPU’s virtual address spaces.”…”�”}”(hjÿh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Khjîh²hubj!)�”}”(hŒKey GPU SVM Components:”h]”hŒKey GPU SVM Components:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Khjîh²hubhï)�”}”(hhh]”(hô)�”}”(hXÊNotifiers: Used for tracking memory intervals and notifying the GPU of changes, notifiers are sized based on a GPU SVM initialization parameter, with a recommendation of 512M or larger. They maintain a Red-BlacK tree and a list of ranges that fall within the notifier interval. Notifiers are tracked within a GPU SVM Red-BlacK tree and list and are dynamically inserted or removed as ranges within the interval are created or destroyed.”h]”hú)�”}”(hhh]”hÿ)�”}”(hXµNotifiers: Used for tracking memory intervals and notifying the GPU of changes, notifiers are sized based on a GPU SVM initialization parameter, with a recommendation of 512M or larger. They maintain a Red-BlacK tree and a list of ranges that fall within the notifier interval. Notifiers are tracked within a GPU SVM Red-BlacK tree and list and are dynamically inserted or removed as ranges within the interval are created or destroyed.”h]”(j)�”}”(hŒ Notifiers:”h]”hŒ Notifiers:”…”�”}”(hj+h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K%hj'ubj)�”}”(hhh]”j!)�”}”(hXªUsed for tracking memory intervals and notifying the GPU of changes, notifiers are sized based on a GPU SVM initialization parameter, with a recommendation of 512M or larger. They maintain a Red-BlacK tree and a list of ranges that fall within the notifier interval. Notifiers are tracked within a GPU SVM Red-BlacK tree and list and are dynamically inserted or removed as ranges within the interval are created or destroyed.”h]”hXªUsed for tracking memory intervals and notifying the GPU of changes, notifiers are sized based on a GPU SVM initialization parameter, with a recommendation of 512M or larger. They maintain a Red-BlacK tree and a list of ranges that fall within the notifier interval. Notifiers are tracked within a GPU SVM Red-BlacK tree and list and are dynamically inserted or removed as ranges within the interval are created or destroyed.”…”�”}”(hj=h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K hj:ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj'ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³j9h´K%hj$ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjubhô)�”}”(hX Ranges: Represent memory ranges mapped in a DRM device and managed by GPU SVM. They are sized based on an array of chunk sizes, which is a GPU SVM initialization parameter, and the CPU address space. Upon GPU fault, the largest aligned chunk that fits within the faulting CPU address space is chosen for the range size. Ranges are expected to be dynamically allocated on GPU fault and removed on an MMU notifier UNMAP event. As mentioned above, ranges are tracked in a notifier's Red-Black tree. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hXñRanges: Represent memory ranges mapped in a DRM device and managed by GPU SVM. They are sized based on an array of chunk sizes, which is a GPU SVM initialization parameter, and the CPU address space. Upon GPU fault, the largest aligned chunk that fits within the faulting CPU address space is chosen for the range size. Ranges are expected to be dynamically allocated on GPU fault and removed on an MMU notifier UNMAP event. As mentioned above, ranges are tracked in a notifier's Red-Black tree. ”h]”(j)�”}”(hŒRanges:”h]”hŒRanges:”…”�”}”(hjoh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K/hjkubj)�”}”(hhh]”j!)�”}”(hXèRepresent memory ranges mapped in a DRM device and managed by GPU SVM. They are sized based on an array of chunk sizes, which is a GPU SVM initialization parameter, and the CPU address space. Upon GPU fault, the largest aligned chunk that fits within the faulting CPU address space is chosen for the range size. Ranges are expected to be dynamically allocated on GPU fault and removed on an MMU notifier UNMAP event. As mentioned above, ranges are tracked in a notifier's Red-Black tree.”h]”hXêRepresent memory ranges mapped in a DRM device and managed by GPU SVM. They are sized based on an array of chunk sizes, which is a GPU SVM initialization parameter, and the CPU address space. Upon GPU fault, the largest aligned chunk that fits within the faulting CPU address space is chosen for the range size. Ranges are expected to be dynamically allocated on GPU fault and removed on an MMU notifier UNMAP event. As mentioned above, ranges are tracked in a notifier’s Red-Black tree.”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K(hj~ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjkubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³j}h´K/hjhubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjdubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjubhô)�”}”(hX8Pages: struct drm_gpusvm_pages holds the DMA mapping state for a range of CPU virtual addresses: the DMA mapped device addresses, the device private pagemap, the IOVA state, the per mapping notifier sequence number, and the drm_device that owns the DMA mappings. A driver embeds one or more struct drm_gpusvm_pages alongside its struct drm_gpusvm_range, choosing one of two layouts: 1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest layout; to mirror a VA range on several devices a driver uses a separate range (and notifier) per device, so the HMM fault is taken once per device. N:1 - one drm_gpusvm_pages per drm_device, all sharing one range and notifier; only the per-device DMA mapping differs. The instances must sit in contiguous memory so a single drm_gpusvm_range_set_unmapped() can mark them all. A driver can keep one instance inline for the single device case and switch to a heap array only when more devices join, e.g.: .. code-block:: c struct driver_range { struct drm_gpusvm_range base; unsigned int num_pages; // 1: inline_pages, >1: pages[] union { struct drm_gpusvm_pages inline_pages; struct drm_gpusvm_pages *pages; }; }; In the N:1 case the driver allocates the pages array with a zeroing allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with drm_gpusvm_init_pages(), and frees each entry with drm_gpusvm_free_pages() plus the array itself, from its range free callback. Each drm_gpusvm_pages is mapped independently by their own drm_device. Each drm_gpusvm_pages must be zero-initialised and initialised with drm_gpusvm_init_pages(), called once per entry. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hXÒPages: struct drm_gpusvm_pages holds the DMA mapping state for a range of CPU virtual addresses: the DMA mapped device addresses, the device private pagemap, the IOVA state, the per mapping notifier sequence number, and the drm_device that owns the DMA mappings. A driver embeds one or more struct drm_gpusvm_pages alongside its struct drm_gpusvm_range, choosing one of two layouts: 1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest layout; to mirror a VA range on several devices a driver uses a separate range (and notifier) per device, so the HMM fault is taken once per device. N:1 - one drm_gpusvm_pages per drm_device, all sharing one range and notifier; only the per-device DMA mapping differs. The instances must sit in contiguous memory so a single drm_gpusvm_range_set_unmapped() can mark them all. A driver can keep one instance inline for the single device case and switch to a heap array only when more devices join, e.g.: .. code-block:: c struct driver_range { struct drm_gpusvm_range base; unsigned int num_pages; // 1: inline_pages, >1: pages[] union { struct drm_gpusvm_pages inline_pages; struct drm_gpusvm_pages *pages; }; }; In the N:1 case the driver allocates the pages array with a zeroing allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with drm_gpusvm_init_pages(), and frees each entry with drm_gpusvm_free_pages() plus the array itself, from its range free callback. Each drm_gpusvm_pages is mapped independently by their own drm_device. Each drm_gpusvm_pages must be zero-initialised and initialised with drm_gpusvm_init_pages(), called once per entry. ”h]”(j)�”}”(hŒPages:”h]”hŒPages:”…”�”}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´KXhj¯ubj)�”}”(hhh]”(j!)�”}”(hXwstruct drm_gpusvm_pages holds the DMA mapping state for a range of CPU virtual addresses: the DMA mapped device addresses, the device private pagemap, the IOVA state, the per mapping notifier sequence number, and the drm_device that owns the DMA mappings. A driver embeds one or more struct drm_gpusvm_pages alongside its struct drm_gpusvm_range, choosing one of two layouts:”h]”hXwstruct drm_gpusvm_pages holds the DMA mapping state for a range of CPU virtual addresses: the DMA mapped device addresses, the device private pagemap, the IOVA state, the per mapping notifier sequence number, and the drm_device that owns the DMA mappings. A driver embeds one or more struct drm_gpusvm_pages alongside its struct drm_gpusvm_range, choosing one of two layouts:”…”�”}”(hjÅh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K2hjÂubj!)�”}”(hŒÔ1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest layout; to mirror a VA range on several devices a driver uses a separate range (and notifier) per device, so the HMM fault is taken once per device.”h]”hŒÔ1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest layout; to mirror a VA range on several devices a driver uses a separate range (and notifier) per device, so the HMM fault is taken once per device.”…”�”}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K:hjÂubj!)�”}”(hXaN:1 - one drm_gpusvm_pages per drm_device, all sharing one range and notifier; only the per-device DMA mapping differs. The instances must sit in contiguous memory so a single drm_gpusvm_range_set_unmapped() can mark them all. A driver can keep one instance inline for the single device case and switch to a heap array only when more devices join, e.g.:”h]”hXaN:1 - one drm_gpusvm_pages per drm_device, all sharing one range and notifier; only the per-device DMA mapping differs. The instances must sit in contiguous memory so a single drm_gpusvm_range_set_unmapped() can mark them all. A driver can keep one instance inline for the single device case and switch to a heap array only when more devices join, e.g.:”…”�”}”(hjãh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K?hjÂubhŒ literal_block”“”)�”}”(hŒÿstruct driver_range { struct drm_gpusvm_range base; unsigned int num_pages; // 1: inline_pages, >1: pages[] union { struct drm_gpusvm_pages inline_pages; struct drm_gpusvm_pages *pages; }; };”h]”hŒÿstruct driver_range { struct drm_gpusvm_range base; unsigned int num_pages; // 1: inline_pages, >1: pages[] union { struct drm_gpusvm_pages inline_pages; struct drm_gpusvm_pages *pages; }; };”…”�”}”hjôsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆŒforce”‰Œlanguage”Œc”Œhighlight_args”}”uh1jòh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´KFhjÂubj!)�”}”(hXÄIn the N:1 case the driver allocates the pages array with a zeroing allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with drm_gpusvm_init_pages(), and frees each entry with drm_gpusvm_free_pages() plus the array itself, from its range free callback. Each drm_gpusvm_pages is mapped independently by their own drm_device. Each drm_gpusvm_pages must be zero-initialised and initialised with drm_gpusvm_init_pages(), called once per entry.”h]”hXÄIn the N:1 case the driver allocates the pages array with a zeroing allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with drm_gpusvm_init_pages(), and frees each entry with drm_gpusvm_free_pages() plus the array itself, from its range free callback. Each drm_gpusvm_pages is mapped independently by their own drm_device. Each drm_gpusvm_pages must be zero-initialised and initialised with drm_gpusvm_init_pages(), called once per entry.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´KQhjÂubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj¯ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³jÁh´KXhj¬ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj¨ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjubhô)�”}”(hŒ�Operations: Define the interface for driver-specific GPU SVM operations such as range allocation, notifier allocation, and invalidations. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒŠOperations: Define the interface for driver-specific GPU SVM operations such as range allocation, notifier allocation, and invalidations. ”h]”(j)�”}”(hŒ Operations:”h]”hŒ Operations:”…”�”}”(hj:h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K\hj6ubj)�”}”(hhh]”j!)�”}”(hŒ}Define the interface for driver-specific GPU SVM operations such as range allocation, notifier allocation, and invalidations.”h]”hŒ}Define the interface for driver-specific GPU SVM operations such as range allocation, notifier allocation, and invalidations.”…”�”}”(hjLh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K[hjIubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj6ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³jHh´K\hj3ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj/ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjubhô)�”}”(hŒ‚Device Memory Allocations: Embedded structure containing enough information for GPU SVM to migrate to / from device memory. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ|Device Memory Allocations: Embedded structure containing enough information for GPU SVM to migrate to / from device memory. ”h]”(j)�”}”(hŒDevice Memory Allocations:”h]”hŒDevice Memory Allocations:”…”�”}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K`hjzubj)�”}”(hhh]”j!)�”}”(hŒ`Embedded structure containing enough information for GPU SVM to migrate to / from device memory.”h]”hŒ`Embedded structure containing enough information for GPU SVM to migrate to / from device memory.”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´K_hj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjzubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³jŒh´K`hjwubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjsubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjubhô)�”}”(hŒ£Device Memory Operations: Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ�Device Memory Operations: Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory. ”h]”(j)�”}”(hŒDevice Memory Operations:”h]”hŒDevice Memory Operations:”…”�”}”(hjÂh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kdhj¾ubj)�”}”(hhh]”j!)�”}”(hŒ‚Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory.”h]”hŒ‚Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory.”…”�”}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´KchjÑubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¾ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³jÐh´Kdhj»ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj·ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjubeh}”(h]”h ]”h"]”h$]”h&]”j›Œ-”uh1hîh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Khjîh²hubj!)�”}”(hX|This layer provides interfaces for allocating, mapping, migrating, and releasing memory ranges between the CPU and GPU. It handles all core memory management interactions (DMA mapping, HMM, and migration) and provides driver-specific virtual functions (vfuncs). This infrastructure is sufficient to build the expected driver components for an SVM implementation as detailed below.”h]”hX|This layer provides interfaces for allocating, mapping, migrating, and releasing memory ranges between the CPU and GPU. It handles all core memory management interactions (DMA mapping, HMM, and migration) and provides driver-specific virtual functions (vfuncs). This infrastructure is sufficient to build the expected driver components for an SVM implementation as detailed below.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kfhjîh²hubj!)�”}”(hŒExpected Driver Components:”h]”hŒExpected Driver Components:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kmhjîh²hubhï)�”}”(hhh]”(hô)�”}”(hŒ¦GPU page fault handler: Used to create ranges and notifiers based on the fault address, optionally migrate the range to device memory, and create GPU bindings. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ GPU page fault handler: Used to create ranges and notifiers based on the fault address, optionally migrate the range to device memory, and create GPU bindings. ”h]”(j)�”}”(hŒGPU page fault handler:”h]”hŒGPU page fault handler:”…”�”}”(hj/h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kqhj+ubj)�”}”(hhh]”j!)�”}”(hŒ‡Used to create ranges and notifiers based on the fault address, optionally migrate the range to device memory, and create GPU bindings.”h]”hŒ‡Used to create ranges and notifiers based on the fault address, optionally migrate the range to device memory, and create GPU bindings.”…”�”}”(hjAh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kphj>ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³j=h´Kqhj(ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj$ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj!ubhô)�”}”(hŒ½Garbage collector: Used to unmap and destroy GPU bindings for ranges. Ranges are expected to be added to the garbage collector upon a MMU_NOTIFY_UNMAP event in notifier callback. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ´Garbage collector: Used to unmap and destroy GPU bindings for ranges. Ranges are expected to be added to the garbage collector upon a MMU_NOTIFY_UNMAP event in notifier callback. ”h]”(j)�”}”(hŒGarbage collector:”h]”hŒGarbage collector:”…”�”}”(hjsh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kvhjoubj)�”}”(hhh]”j!)�”}”(hŒ Used to unmap and destroy GPU bindings for ranges. Ranges are expected to be added to the garbage collector upon a MMU_NOTIFY_UNMAP event in notifier callback.”h]”hŒ Used to unmap and destroy GPU bindings for ranges. Ranges are expected to be added to the garbage collector upon a MMU_NOTIFY_UNMAP event in notifier callback.”…”�”}”(hj…h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kthj‚ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjoubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³j�h´Kvhjlubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjhubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj!ubhô)�”}”(hŒQNotifier callback: Used to invalidate and DMA unmap GPU bindings for ranges. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒNNotifier callback: Used to invalidate and DMA unmap GPU bindings for ranges. ”h]”(j)�”}”(hŒNotifier callback:”h]”hŒNotifier callback:”…”�”}”(hj·h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kzhj³ubj)�”}”(hhh]”j!)�”}”(hŒ9Used to invalidate and DMA unmap GPU bindings for ranges.”h]”hŒ9Used to invalidate and DMA unmap GPU bindings for ranges.”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´KyhjÆubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj³ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³jÅh´Kzhj°ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj¬ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj!ubeh}”(h]”h ]”h"]”h$]”h&]”j›juh1hîh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:70: ./drivers/gpu/drm/drm_gpusvm.c”h´Kohjîh²hubj!)�”}”(hŒaGPU SVM handles locking for core MM interactions, i.e., it locks/unlocks the mmap lock as needed.”h]”hŒaGPU SVM handles locking for core MM interactions, i.e., it locks/unlocks the mmap lock as needed.”…”�”}”(hj÷h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:73: ./drivers/gpu/drm/drm_gpusvm.c”h´Khjîh²hubj!)�”}”(hX-GPU SVM introduces a global notifier lock, which safeguards the notifier's range RB tree and list, as well as the range's DMA mappings and sequence number. GPU SVM manages all necessary locking and unlocking operations, except for the recheck range's pages being valid (drm_gpusvm_pages_valid) when the driver is committing GPU bindings. This lock corresponds to the ``driver->update`` lock mentioned in Documentation/mm/hmm.rst. Future revisions may transition from a GPU SVM global lock to a per-notifier lock if finer-grained locking is deemed necessary.”h]”(hXuGPU SVM introduces a global notifier lock, which safeguards the notifier’s range RB tree and list, as well as the range’s DMA mappings and sequence number. GPU SVM manages all necessary locking and unlocking operations, except for the recheck range’s pages being valid (drm_gpusvm_pages_valid) when the driver is committing GPU bindings. This lock corresponds to the ”…”�”}”(hjh²hh³Nh´NubhŒliteral”“”)�”}”(hŒ``driver->update``”h]”hŒdriver->update”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒ¬ lock mentioned in Documentation/mm/hmm.rst. Future revisions may transition from a GPU SVM global lock to a per-notifier lock if finer-grained locking is deemed necessary.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:73: ./drivers/gpu/drm/drm_gpusvm.c”h´K‚hjîh²hubj!)�”}”(hXÝIn addition to the locking mentioned above, the driver should implement a lock to safeguard core GPU SVM function calls that modify state, such as drm_gpusvm_range_find_or_insert and drm_gpusvm_range_remove. This lock is denoted as 'driver_svm_lock' in code examples. Finer grained driver side locking should also be possible for concurrent GPU fault processing within a single GPU SVM. The 'driver_svm_lock' can be via drm_gpusvm_driver_set_lock to add annotations to GPU SVM.”h]”hXåIn addition to the locking mentioned above, the driver should implement a lock to safeguard core GPU SVM function calls that modify state, such as drm_gpusvm_range_find_or_insert and drm_gpusvm_range_remove. This lock is denoted as ‘driver_svm_lock’ in code examples. Finer grained driver side locking should also be possible for concurrent GPU fault processing within a single GPU SVM. The ‘driver_svm_lock’ can be via drm_gpusvm_driver_set_lock to add annotations to GPU SVM.”…”�”}”(hj)h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:73: ./drivers/gpu/drm/drm_gpusvm.c”h´KŒhjîh²hubj!)�”}”(hXKPartial unmapping of ranges (e.g., 1M out of 2M is unmapped by CPU resulting in MMU_NOTIFY_UNMAP event) presents several challenges, with the main one being that a subset of the range still has CPU and GPU mappings. If the backing store for the range is in device memory, a subset of the backing store has references. One option would be to split the range and device memory backing store, but the implementation for this would be quite complicated. Given that partial unmappings are rare and driver-defined range sizes are relatively small, GPU SVM does not support splitting of ranges.”h]”hXKPartial unmapping of ranges (e.g., 1M out of 2M is unmapped by CPU resulting in MMU_NOTIFY_UNMAP event) presents several challenges, with the main one being that a subset of the range still has CPU and GPU mappings. If the backing store for the range is in device memory, a subset of the backing store has references. One option would be to split the range and device memory backing store, but the implementation for this would be quite complicated. Given that partial unmappings are rare and driver-defined range sizes are relatively small, GPU SVM does not support splitting of ranges.”…”�”}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:76: ./drivers/gpu/drm/drm_gpusvm.c”h´K˜hjîh²hubj!)�”}”(hXWith no support for range splitting, upon partial unmapping of a range, the driver is expected to invalidate and destroy the entire range. If the range has device memory as its backing, the driver is also expected to migrate any remaining pages back to RAM.”h]”hXWith no support for range splitting, upon partial unmapping of a range, the driver is expected to invalidate and destroy the entire range. If the range has device memory as its backing, the driver is also expected to migrate any remaining pages back to RAM.”…”�”}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:76: ./drivers/gpu/drm/drm_gpusvm.c”h´K¡hjîh²hubj!)�”}”(hŒ¢This section provides three examples of how to build the expected driver components: the GPU page fault handler, the garbage collector, and the notifier callback.”h]”hŒ¢This section provides three examples of how to build the expected driver components: the GPU page fault handler, the garbage collector, and the notifier callback.”…”�”}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´Kªhjîh²hubj!)�”}”(hŒÌThe generic code provided does not include logic for complex migration policies, optimized invalidations, fined grained driver locking, or other potentially required driver locking (e.g., DMA-resv locks).”h]”hŒÌThe generic code provided does not include logic for complex migration policies, optimized invalidations, fined grained driver locking, or other potentially required driver locking (e.g., DMA-resv locks).”…”�”}”(hjeh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´K®hjîh²hubhŒenumerated_list”“”)�”}”(hhh]”hô)�”}”(hŒGPU page fault handler ”h]”j!)�”}”(hŒGPU page fault handler”h]”hŒGPU page fault handler”…”�”}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´K²hjyubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjvubah}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ)”uh1jthjîh²hh³Nh´Nubjó)�”}”(hX¬ struct driver_range { struct drm_gpusvm_range base; struct drm_gpusvm_pages pages; }; int driver_bind_range(struct drm_gpusvm *gpusvm, struct driver_range *drange) { int err = 0; driver_alloc_and_setup_memory_for_bind(gpusvm, drange); drm_gpusvm_notifier_lock(gpusvm); if (drm_gpusvm_pages_valid(gpusvm, &drange->pages)) driver_commit_bind(gpusvm, drange); else err = -EAGAIN; drm_gpusvm_notifier_unlock(gpusvm); return err; } int driver_gpu_fault(struct drm_gpusvm *gpusvm, unsigned long fault_addr, unsigned long gpuva_start, unsigned long gpuva_end) { struct drm_gpusvm_ctx ctx = {}; struct driver_range *drange; struct drm_gpusvm_range *range; int err; driver_svm_lock(); retry: // Always process UNMAPs first so view of GPU SVM ranges is current driver_garbage_collector(gpusvm); range = drm_gpusvm_range_find_or_insert(gpusvm, fault_addr, gpuva_start, gpuva_end, &ctx); if (IS_ERR(range)) { err = PTR_ERR(range); goto unlock; } drange = container_of(range, struct driver_range, base); if (driver_migration_policy(range)) { err = drm_pagemap_populate_mm(driver_choose_drm_pagemap(), gpuva_start, gpuva_end, gpusvm->mm, ctx->timeslice_ms); if (err) // CPU mappings may have changed goto retry; } err = drm_gpusvm_get_pages(gpusvm, &drange->pages, gpusvm->mm, &range->notifier->notifier, drm_gpusvm_range_start(range), drm_gpusvm_range_end(range), &ctx); if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM) { // CPU mappings changed if (err == -EOPNOTSUPP) drm_gpusvm_range_evict(gpusvm, range); goto retry; } else if (err) { goto unlock; } err = driver_bind_range(gpusvm, drange); if (err == -EAGAIN) // CPU mappings changed goto retry unlock: driver_svm_unlock(); return err; }”h]”hX¬ struct driver_range { struct drm_gpusvm_range base; struct drm_gpusvm_pages pages; }; int driver_bind_range(struct drm_gpusvm *gpusvm, struct driver_range *drange) { int err = 0; driver_alloc_and_setup_memory_for_bind(gpusvm, drange); drm_gpusvm_notifier_lock(gpusvm); if (drm_gpusvm_pages_valid(gpusvm, &drange->pages)) driver_commit_bind(gpusvm, drange); else err = -EAGAIN; drm_gpusvm_notifier_unlock(gpusvm); return err; } int driver_gpu_fault(struct drm_gpusvm *gpusvm, unsigned long fault_addr, unsigned long gpuva_start, unsigned long gpuva_end) { struct drm_gpusvm_ctx ctx = {}; struct driver_range *drange; struct drm_gpusvm_range *range; int err; driver_svm_lock(); retry: // Always process UNMAPs first so view of GPU SVM ranges is current driver_garbage_collector(gpusvm); range = drm_gpusvm_range_find_or_insert(gpusvm, fault_addr, gpuva_start, gpuva_end, &ctx); if (IS_ERR(range)) { err = PTR_ERR(range); goto unlock; } drange = container_of(range, struct driver_range, base); if (driver_migration_policy(range)) { err = drm_pagemap_populate_mm(driver_choose_drm_pagemap(), gpuva_start, gpuva_end, gpusvm->mm, ctx->timeslice_ms); if (err) // CPU mappings may have changed goto retry; } err = drm_gpusvm_get_pages(gpusvm, &drange->pages, gpusvm->mm, &range->notifier->notifier, drm_gpusvm_range_start(range), drm_gpusvm_range_end(range), &ctx); if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM) { // CPU mappings changed if (err == -EOPNOTSUPP) drm_gpusvm_range_evict(gpusvm, range); goto retry; } else if (err) { goto unlock; } err = driver_bind_range(gpusvm, drange); if (err == -EAGAIN) // CPU mappings changed goto retry unlock: driver_svm_unlock(); return err; }”…”�”}”hj�sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆj‰jjj}”uh1jòh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´K´hjîh²hubju)�”}”(hhh]”hô)�”}”(hŒGarbage Collector ”h]”j!)�”}”(hŒGarbage Collector”h]”hŒGarbage Collector”…”�”}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´Kþhj°ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj­ubah}”(h]”h ]”h"]”h$]”h&]”j˜j™jšhj›jœŒstart”Kuh1jthjîh²hh³Nh´Nubjó)�”}”(hXU// The driver owns the drm_gpusvm_pages lifecycle. ops->range_free is // the final fallback: drm_gpusvm_free_pages() unmaps any // lingering DMA mapping and a no-op if already unmapped and frees the // dma_addr array. The normal flow is to DMA unmap before // drm_gpusvm_range_remove() (before the range leaves the tree). void driver_range_free(struct drm_gpusvm_range *range) { struct driver_range *drange = container_of(range, struct driver_range, base); drm_gpusvm_free_pages(range->gpusvm, &drange->pages, drm_gpusvm_range_size(range) >> PAGE_SHIFT); kfree(drange); } void __driver_garbage_collector(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) { assert_driver_svm_locked(gpusvm); // Partial unmap, migrate any remaining device memory pages back to RAM if (range->flags.partial_unmap) drm_gpusvm_range_evict(gpusvm, range); driver_unbind_range(range); // The pages must be DMA unmapped before drm_gpusvm_range_remove() // , so a range is never off the MMU interval tree while still DMA // mapped as the original drmsvm design flow. Otherwise a concurrent CPU // munmap's notifier could miss this range and free pages still mapped // for device DMA. This is the normal unmap point. drm_gpusvm_unmap_pages(gpusvm, &drange->pages, drm_gpusvm_range_size(range) >> PAGE_SHIFT, &(struct drm_gpusvm_ctx){ .in_notifier = false }); drm_gpusvm_range_remove(gpusvm, range); } void driver_garbage_collector(struct drm_gpusvm *gpusvm) { assert_driver_svm_locked(gpusvm); for_each_range_in_garbage_collector(gpusvm, range) __driver_garbage_collector(gpusvm, range); }”h]”hXU// The driver owns the drm_gpusvm_pages lifecycle. ops->range_free is // the final fallback: drm_gpusvm_free_pages() unmaps any // lingering DMA mapping and a no-op if already unmapped and frees the // dma_addr array. The normal flow is to DMA unmap before // drm_gpusvm_range_remove() (before the range leaves the tree). void driver_range_free(struct drm_gpusvm_range *range) { struct driver_range *drange = container_of(range, struct driver_range, base); drm_gpusvm_free_pages(range->gpusvm, &drange->pages, drm_gpusvm_range_size(range) >> PAGE_SHIFT); kfree(drange); } void __driver_garbage_collector(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) { assert_driver_svm_locked(gpusvm); // Partial unmap, migrate any remaining device memory pages back to RAM if (range->flags.partial_unmap) drm_gpusvm_range_evict(gpusvm, range); driver_unbind_range(range); // The pages must be DMA unmapped before drm_gpusvm_range_remove() // , so a range is never off the MMU interval tree while still DMA // mapped as the original drmsvm design flow. Otherwise a concurrent CPU // munmap's notifier could miss this range and free pages still mapped // for device DMA. This is the normal unmap point. drm_gpusvm_unmap_pages(gpusvm, &drange->pages, drm_gpusvm_range_size(range) >> PAGE_SHIFT, &(struct drm_gpusvm_ctx){ .in_notifier = false }); drm_gpusvm_range_remove(gpusvm, range); } void driver_garbage_collector(struct drm_gpusvm *gpusvm) { assert_driver_svm_locked(gpusvm); for_each_range_in_garbage_collector(gpusvm, range) __driver_garbage_collector(gpusvm, range); }”…”�”}”hjÐsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆj‰jjj}”uh1jòh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´Mhjîh²hubju)�”}”(hhh]”hô)�”}”(hŒNotifier callback ”h]”j!)�”}”(hŒNotifier callback”h]”hŒNotifier callback”…”�”}”(hjçh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´M.hjãubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjàubah}”(h]”h ]”h"]”h$]”h&]”j˜j™jšhj›jœjÏKuh1jthjîh²hh³Nh´Nubjó)�”}”(hXvoid driver_invalidation(struct drm_gpusvm *gpusvm, struct drm_gpusvm_notifier *notifier, const struct mmu_notifier_range *mmu_range) { struct drm_gpusvm_ctx ctx = { .in_notifier = true, }; struct drm_gpusvm_range *range = NULL; struct driver_range *drange; driver_invalidate_device_pages(gpusvm, mmu_range->start, mmu_range->end); drm_gpusvm_for_each_range(range, notifier, mmu_range->start, mmu_range->end) { drange = container_of(range, struct driver_range, base); drm_gpusvm_unmap_pages(gpusvm, &drange->pages, drm_gpusvm_range_size(range) >> PAGE_SHIFT, &ctx); if (mmu_range->event != MMU_NOTIFY_UNMAP) continue; drm_gpusvm_range_set_unmapped(range, &drange->pages, 1, mmu_range); driver_garbage_collector_add(gpusvm, range); } }”h]”hXvoid driver_invalidation(struct drm_gpusvm *gpusvm, struct drm_gpusvm_notifier *notifier, const struct mmu_notifier_range *mmu_range) { struct drm_gpusvm_ctx ctx = { .in_notifier = true, }; struct drm_gpusvm_range *range = NULL; struct driver_range *drange; driver_invalidate_device_pages(gpusvm, mmu_range->start, mmu_range->end); drm_gpusvm_for_each_range(range, notifier, mmu_range->start, mmu_range->end) { drange = container_of(range, struct driver_range, base); drm_gpusvm_unmap_pages(gpusvm, &drange->pages, drm_gpusvm_range_size(range) >> PAGE_SHIFT, &ctx); if (mmu_range->event != MMU_NOTIFY_UNMAP) continue; drm_gpusvm_range_set_unmapped(range, &drange->pages, 1, mmu_range); driver_garbage_collector_add(gpusvm, range); } }”…”�”•oP}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆj‰jjj}”uh1jòh³Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”h´M0hjîh²hubeh}”(h]”Œoverview-of-baseline-design”ah ]”h"]”Œoverview of baseline design”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KDubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒOverview of drm_pagemap design”h]”hŒOverview of drm_pagemap design”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhjh²hh³hÇh´KSubj!)�”}”(hXÇThe DRM pagemap layer is intended to augment the dev_pagemap functionality by providing a way to populate a struct mm_struct virtual range with device private pages and to provide helpers to abstract device memory allocations, to migrate memory back and forth between device memory and system RAM and to handle access (and in the future migration) between devices implementing a fast interconnect that is not necessarily visible to the rest of the system.”h]”hXÇThe DRM pagemap layer is intended to augment the dev_pagemap functionality by providing a way to populate a struct mm_struct virtual range with device private pages and to provide helpers to abstract device memory allocations, to migrate memory back and forth between device memory and system RAM and to handle access (and in the future migration) between devices implementing a fast interconnect that is not necessarily visible to the rest of the system.”…”�”}”(hj+h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:85: ./drivers/gpu/drm/drm_pagemap.c”h´Khjh²hubj!)�”}”(hXtTypically the DRM pagemap receives requests from one or more DRM GPU SVM instances to populate struct mm_struct virtual ranges with memory, and the migration is best effort only and may thus fail. The implementation should also handle device unbinding by blocking (return an -ENODEV) error for new population requests and after that migrate all device pages to system ram.”h]”hXtTypically the DRM pagemap receives requests from one or more DRM GPU SVM instances to populate struct mm_struct virtual ranges with memory, and the migration is best effort only and may thus fail. The implementation should also handle device unbinding by blocking (return an -ENODEV) error for new population requests and after that migrate all device pages to system ram.”…”�”}”(hj:h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:85: ./drivers/gpu/drm/drm_pagemap.c”h´Khjh²hubj!)�”}”(hXzMigration granularity typically follows the GPU SVM range requests, but if there are clashes, due to races or due to the fact that multiple GPU SVM instances have different views of the ranges used, and because of that parts of a requested range is already present in the requested device memory, the implementation has a variety of options. It can fail and it can choose to populate only the part of the range that isn't already in device memory, and it can evict the range to system before trying to migrate. Ideally an implementation would just try to migrate the missing part of the range and allocate just enough memory to do so.”h]”hX|Migration granularity typically follows the GPU SVM range requests, but if there are clashes, due to races or due to the fact that multiple GPU SVM instances have different views of the ranges used, and because of that parts of a requested range is already present in the requested device memory, the implementation has a variety of options. It can fail and it can choose to populate only the part of the range that isn’t already in device memory, and it can evict the range to system before trying to migrate. Ideally an implementation would just try to migrate the missing part of the range and allocate just enough memory to do so.”…”�”}”(hjIh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K"hjh²hubj!)�”}”(hXTWhen migrating to system memory as a response to a cpu fault or a device memory eviction request, currently a full device memory allocation is migrated back to system. Moving forward this might need improvement for situations where a single page needs bouncing between system memory and device memory due to, for example, atomic operations.”h]”hXTWhen migrating to system memory as a response to a cpu fault or a device memory eviction request, currently a full device memory allocation is migrated back to system. Moving forward this might need improvement for situations where a single page needs bouncing between system memory and device memory due to, for example, atomic operations.”…”�”}”(hjXh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K,hjh²hubj!)�”}”(hŒKey DRM pagemap components:”h]”hŒKey DRM pagemap components:”…”�”}”(hjgh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K2hjh²hubhï)�”}”(hhh]”(hô)�”}”(hŒŠDevice Memory Allocations: Embedded structure containing enough information for the drm_pagemap to migrate to / from device memory. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ„Device Memory Allocations: Embedded structure containing enough information for the drm_pagemap to migrate to / from device memory. ”h]”(j)�”}”(hŒDevice Memory Allocations:”h]”hŒDevice Memory Allocations:”…”�”}”(hj„h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K6hj€ubj)�”}”(hhh]”j!)�”}”(hŒhEmbedded structure containing enough information for the drm_pagemap to migrate to / from device memory.”h]”hŒhEmbedded structure containing enough information for the drm_pagemap to migrate to / from device memory.”…”�”}”(hj–h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K5hj“ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj€ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³j’h´K6hj}ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjyubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjvubhô)�”}”(hŒ¤Device Memory Operations: Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory. ”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒžDevice Memory Operations: Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory. ”h]”(j)�”}”(hŒDevice Memory Operations:”h]”hŒDevice Memory Operations:”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K;hjÄubj)�”}”(hhh]”j!)�”}”(hŒ‚Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory.”h]”hŒ‚Define the interface for driver-specific device memory operations release memory, populate pfns, and copy to / from device memory.”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K9hj×ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÄubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³jÖh´K;hjÁubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj½ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjvubeh}”(h]”h ]”h"]”h$]”h&]”j›juh1hîh³Œ\/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:88: ./drivers/gpu/drm/drm_pagemap.c”h´K4hjh²hubeh}”(h]”Œoverview-of-drm-pagemap-design”ah ]”h"]”Œoverview of drm_pagemap design”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´KSubhÉ)�”}”(hhh]”(hÎ)�”}”(hŒPossible future design features”h]”hŒPossible future design features”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj h²hh³hÇh´K\ubhï)�”}”(hhh]”(hô)�”}”(hŒúConcurrent GPU faults * CPU faults are concurrent so makes sense to have concurrent GPU faults. * Should be possible with fined grained locking in the driver GPU fault handler. * No expected GPU SVM changes required.”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒÜConcurrent GPU faults * CPU faults are concurrent so makes sense to have concurrent GPU faults. * Should be possible with fined grained locking in the driver GPU fault handler. * No expected GPU SVM changes required.”h]”(j)�”}”(hŒConcurrent GPU faults”h]”hŒConcurrent GPU faults”…”�”}”(hj/ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´Kbhj+ ubj)�”}”(hhh]”hï)�”}”(hhh]”(hô)�”}”(hŒGCPU faults are concurrent so makes sense to have concurrent GPU faults.”h]”j!)�”}”(hŒGCPU faults are concurrent so makes sense to have concurrent GPU faults.”h]”hŒGCPU faults are concurrent so makes sense to have concurrent GPU faults.”…”�”}”(hjG h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K_hjC ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj@ ubhô)�”}”(hŒNShould be possible with fined grained locking in the driver GPU fault handler.”h]”j!)�”}”(hŒNShould be possible with fined grained locking in the driver GPU fault handler.”h]”hŒNShould be possible with fined grained locking in the driver GPU fault handler.”…”�”}”(hj_ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kahj[ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj@ ubhô)�”}”(hŒ%No expected GPU SVM changes required.”h]”j!)�”}”(hju h]”hŒ%No expected GPU SVM changes required.”…”�”}”(hjw h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kchjs ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj@ ubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´K_hj= ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´Kbhj( ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj$ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³Nh´Nubhô)�”}”(hŒqRanges with mixed system and device pages * Can be added if required to drm_gpusvm_get_pages fairly easily.”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒkRanges with mixed system and device pages * Can be added if required to drm_gpusvm_get_pages fairly easily.”h]”(j)�”}”(hŒ)Ranges with mixed system and device pages”h]”hŒ)Ranges with mixed system and device pages”…”�”}”(hj³ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´Kdhj¯ ubj)�”}”(hhh]”hï)�”}”(hhh]”hô)�”}”(hŒ?Can be added if required to drm_gpusvm_get_pages fairly easily.”h]”j!)�”}”(hjÉ h]”hŒ?Can be added if required to drm_gpusvm_get_pages fairly easily.”…”�”}”(hjË h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KehjÇ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjÄ ubah}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´KehjÁ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¯ ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´Kdhj¬ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj¨ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³Nh´Nubhô)�”}”(hŒ­Multi-GPU support * Work in progress and patches expected after initially landing on GPU SVM. * Ideally can be done with little to no changes to GPU SVM.”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ›Multi-GPU support * Work in progress and patches expected after initially landing on GPU SVM. * Ideally can be done with little to no changes to GPU SVM.”h]”(j)�”}”(hŒMulti-GPU support”h]”hŒMulti-GPU support”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´Khhj ubj)�”}”(hhh]”hï)�”}”(hhh]”(hô)�”}”(hŒIWork in progress and patches expected after initially landing on GPU SVM.”h]”j!)�”}”(hŒIWork in progress and patches expected after initially landing on GPU SVM.”h]”hŒIWork in progress and patches expected after initially landing on GPU SVM.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kghj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj ubhô)�”}”(hŒ9Ideally can be done with little to no changes to GPU SVM.”h]”j!)�”}”(hj5 h]”hŒ9Ideally can be done with little to no changes to GPU SVM.”…”�”}”(hj7 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kihj3 ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj ubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´Kghj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´Khhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjü ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³Nh´Nubhô)�”}”(hŒQDrop ranges in favor of radix tree * May be desirable for faster notifiers.”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒKDrop ranges in favor of radix tree * May be desirable for faster notifiers.”h]”(j)�”}”(hŒ"Drop ranges in favor of radix tree”h]”hŒ"Drop ranges in favor of radix tree”…”�”}”(hjs h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´Kjhjo ubj)�”}”(hhh]”hï)�”}”(hhh]”hô)�”}”(hŒ&May be desirable for faster notifiers.”h]”j!)�”}”(hj‰ h]”hŒ&May be desirable for faster notifiers.”…”�”}”(hj‹ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kkhj‡ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj„ ubah}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´Kkhj� ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjo ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´Kjhjl ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjh ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³Nh´Nubhô)�”}”(hXCompound device pages * Nvidia, AMD, and Intel all have agreed expensive core MM functions in migrate device layer are a performance bottleneck, having compound device pages should help increase performance by reducing the number of these expensive calls.”h]”hú)�”}”(hhh]”hÿ)�”}”(hXCompound device pages * Nvidia, AMD, and Intel all have agreed expensive core MM functions in migrate device layer are a performance bottleneck, having compound device pages should help increase performance by reducing the number of these expensive calls.”h]”(j)�”}”(hŒCompound device pages”h]”hŒCompound device pages”…”�”}”(hjÇ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´Kohjà ubj)�”}”(hhh]”hï)�”}”(hhh]”hô)�”}”(hŒçNvidia, AMD, and Intel all have agreed expensive core MM functions in migrate device layer are a performance bottleneck, having compound device pages should help increase performance by reducing the number of these expensive calls.”h]”j!)�”}”(hŒçNvidia, AMD, and Intel all have agreed expensive core MM functions in migrate device layer are a performance bottleneck, having compound device pages should help increase performance by reducing the number of these expensive calls.”h]”hŒçNvidia, AMD, and Intel all have agreed expensive core MM functions in migrate device layer are a performance bottleneck, having compound device pages should help increase performance by reducing the number of these expensive calls.”…”�”}”(hjß h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KmhjÛ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhjØ ubah}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´KmhjÕ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjà ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´KohjÀ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj¼ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³Nh´Nubhô)�”}”(hŒ°Higher order dma mapping for migration * 4k dma mapping adversely affects migration performance on Intel hardware, higher order (2M) dma mapping should help here.”h]”hú)�”}”(hhh]”hÿ)�”}”(hŒ¤Higher order dma mapping for migration * 4k dma mapping adversely affects migration performance on Intel hardware, higher order (2M) dma mapping should help here.”h]”(j)�”}”(hŒ&Higher order dma mapping for migration”h]”hŒ&Higher order dma mapping for migration”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÇh´Krhj ubj)�”}”(hhh]”hï)�”}”(hhh]”hô)�”}”(hŒy4k dma mapping adversely affects migration performance on Intel hardware, higher order (2M) dma mapping should help here.”h]”j!)�”}”(hŒy4k dma mapping adversely affects migration performance on Intel hardware, higher order (2M) dma mapping should help here.”h]”hŒy4k dma mapping adversely affects migration performance on Intel hardware, higher order (2M) dma mapping should help here.”…”�”}”(hj4 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Krhj0 ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj- ubah}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´Krhj* ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hþh³hÇh´Krhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hùhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³Nh´Nubhô)�”}”(hŒ5Build common userptr implementation on top of GPU SVM”h]”j!)�”}”(hjh h]”hŒ5Build common userptr implementation on top of GPU SVM”…”�”}”(hjj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kthjf ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³hÇh´Nubhô)�”}”(hŒ9Driver side madvise implementation and migration policies”h]”j!)�”}”(hj h]”hŒ9Driver side madvise implementation and migration policies”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kuhj} ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³hÇh´Nubhô)�”}”(hŒJPull in pending dma-mapping API changes from Leon / Nvidia when these land”h]”j!)�”}”(hj– h]”hŒJPull in pending dma-mapping API changes from Leon / Nvidia when these land”…”�”}”(hj˜ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Kvhj” ubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhj! h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j›jœuh1hîh³hÇh´K^hj h²hubeh}”(h]”Œpossible-future-design-features”ah ]”h"]”Œpossible future design features”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K\ubeh}”(h]”Œgpu-svm-section”ah ]”h"]”Œgpu svm section”ah$]”h&]”uh1hÈhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)�”}”(hÍNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jä Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(j¾ j» jëjèjjj j j¶ j³ uŒ nametypes”}”(j¾ ‰jë‰j‰j ‰j¶ ‰uh}”(j» hÊjèhÝjjîj jj³ j uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”(hŒsystem_message”“”)�”}”(hhh]”j!)�”}”(hŒ:Enumerated list start value not ordinal-1: "2" (ordinal 2)”h]”hŒ>Enumerated list start value not ordinal-1: “2â€� (ordinal 2)”…”�”}”(hjK h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjH ubah}”(h]”h ]”h"]”h$]”h&]”Œlevel”KŒtype”ŒINFO”Œsource”Œ[/var/lib/git/docbuild/linux/Documentation/gpu/rfc/gpusvm:79: ./drivers/gpu/drm/drm_gpusvm.c”Œline”MLuh1jF hjîh²hh³Nh´NubjG )�”}”(hhh]”j!)�”}”(hŒ:Enumerated list start value not ordinal-1: "3" (ordinal 3)”h]”hŒ>Enumerated list start value not ordinal-1: “3â€� (ordinal 3)”…”�”}”(hjh h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hje ubah}”(h]”h ]”h"]”h$]”h&]”Œlevel”KŒtype”ja Œsource”jc Œline”MLuh1jF hjîh²hh³Nh´NubeŒtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.