]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amdkfd: Fix SVM map/unmap address conversion for non-4k page sizes
authorDonet Tom <donettom@linux.ibm.com>
Mon, 12 Jan 2026 14:06:55 +0000 (19:36 +0530)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 14 Jan 2026 19:28:48 +0000 (14:28 -0500)
SVM range size is tracked using the system page size. The range start and
end are aligned to system page-sized PFNs, so the total SVM range size
equals the total number of pages in the SVM range multiplied by the system
page size.

The SVM range map/unmap functions pass these system page-sized PFN numbers
to amdgpu_vm_update_range(), which expects PFNs based on the GPU page size
(4K). On non-4K page systems, this mismatch causes only part of the SVM
range to be mapped in the GPU page table, while the rest remains unmapped.
If the GPU accesses an unmapped address within the same range, it results
in a GPU page fault.

To fix this, the required conversion has been added in both
svm_range_map_to_gpu() and svm_range_unmap_from_gpu(), ensuring that all
pages in the SVM range are correctly mapped on non-4K systems.

Acked-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Philip Yang <Philip.Yang@amd.com>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Signed-off-by: Donet Tom <donettom@linux.ibm.com>
Signed-off-by: Felix Kuehling <felix.kuehling@amd.com>
Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdkfd/kfd_svm.c

index 1ed08388d364653b121d214a19126496a4f86a4d..35036d47657be178ed99ca9549cdb99b5bcf3856 100644 (file)
@@ -1355,11 +1355,16 @@ svm_range_unmap_from_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,
                         struct dma_fence **fence)
 {
        uint64_t init_pte_value = adev->gmc.init_pte_flags;
+       uint64_t gpu_start, gpu_end;
 
-       pr_debug("[0x%llx 0x%llx]\n", start, last);
+       /* Convert CPU page range to GPU page range */
+       gpu_start = start * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
+       gpu_end = (last + 1) * AMDGPU_GPU_PAGES_IN_CPU_PAGE - 1;
 
-       return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, start,
-                                     last, init_pte_value, 0, 0, NULL, NULL,
+       pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last,
+               gpu_start, gpu_end);
+       return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start,
+                                     gpu_end, init_pte_value, 0, 0, NULL, NULL,
                                      fence);
 }
 
@@ -1439,6 +1444,9 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange,
                 last_start, last_start + npages - 1, readonly);
 
        for (i = offset; i < offset + npages; i++) {
+               uint64_t gpu_start;
+               uint64_t gpu_end;
+
                last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN;
                dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN;
 
@@ -1456,17 +1464,22 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange,
                if (readonly)
                        pte_flags &= ~AMDGPU_PTE_WRITEABLE;
 
-               pr_debug("svms 0x%p map [0x%lx 0x%llx] vram %d PTE 0x%llx\n",
-                        prange->svms, last_start, prange->start + i,
-                        (last_domain == SVM_RANGE_VRAM_DOMAIN) ? 1 : 0,
-                        pte_flags);
 
                /* For dGPU mode, we use same vm_manager to allocate VRAM for
                 * different memory partition based on fpfn/lpfn, we should use
                 * same vm_manager.vram_base_offset regardless memory partition.
                 */
+               gpu_start = last_start * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
+               gpu_end = (prange->start + i + 1) * AMDGPU_GPU_PAGES_IN_CPU_PAGE - 1;
+
+               pr_debug("svms 0x%p map CPU[0x%lx 0x%llx] GPU[0x%llx 0x%llx] vram %d PTE 0x%llx\n",
+                        prange->svms, last_start, prange->start + i,
+                        gpu_start, gpu_end,
+                        (last_domain == SVM_RANGE_VRAM_DOMAIN) ? 1 : 0,
+                        pte_flags);
+
                r = amdgpu_vm_update_range(adev, vm, false, false, flush_tlb, true,
-                                          NULL, last_start, prange->start + i,
+                                          NULL, gpu_start, gpu_end,
                                           pte_flags,
                                           (last_start - prange->start) << PAGE_SHIFT,
                                           bo_adev ? bo_adev->vm_manager.vram_base_offset : 0,