Merge tag 'mtd/fixes-for-4.20-rc5' of git://git.infradead.org/linux-mtd
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_vm.c
index 352b304090602e342ef6f584acab90edf126f51a..0877ff9a959445ad77a263f2ba1105ec5e795822 100644 (file)
@@ -181,7 +181,7 @@ static unsigned amdgpu_vm_num_entries(struct amdgpu_device *adev,
 
        if (level == adev->vm_manager.root_level)
                /* For the root directory */
-               return round_up(adev->vm_manager.max_pfn, 1 << shift) >> shift;
+               return round_up(adev->vm_manager.max_pfn, 1ULL << shift) >> shift;
        else if (level != AMDGPU_VM_PTB)
                /* Everything in between */
                return 512;
@@ -1632,13 +1632,6 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
                        continue;
                }
 
-               /* First check if the entry is already handled */
-               if (cursor.pfn < frag_start) {
-                       cursor.entry->huge = true;
-                       amdgpu_vm_pt_next(adev, &cursor);
-                       continue;
-               }
-
                /* If it isn't already handled it can't be a huge page */
                if (cursor.entry->huge) {
                        /* Add the entry to the relocated list to update it. */
@@ -1663,9 +1656,11 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
                        if (!amdgpu_vm_pt_descendant(adev, &cursor))
                                return -ENOENT;
                        continue;
-               } else if (frag >= parent_shift) {
+               } else if (frag >= parent_shift &&
+                          cursor.level - 1 != adev->vm_manager.root_level) {
                        /* If the fragment size is even larger than the parent
-                        * shift we should go up one level and check it again.
+                        * shift we should go up one level and check it again
+                        * unless one level up is the root level.
                         */
                        if (!amdgpu_vm_pt_ancestor(&cursor))
                                return -ENOENT;
@@ -1673,10 +1668,10 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
                }
 
                /* Looks good so far, calculate parameters for the update */
-               incr = AMDGPU_GPU_PAGE_SIZE << shift;
+               incr = (uint64_t)AMDGPU_GPU_PAGE_SIZE << shift;
                mask = amdgpu_vm_entries_mask(adev, cursor.level);
                pe_start = ((cursor.pfn >> shift) & mask) * 8;
-               entry_end = (mask + 1) << shift;
+               entry_end = (uint64_t)(mask + 1) << shift;
                entry_end += cursor.pfn & ~(entry_end - 1);
                entry_end = min(entry_end, end);
 
@@ -1689,7 +1684,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
                                              flags | AMDGPU_PTE_FRAG(frag));
 
                        pe_start += nptes * 8;
-                       dst += nptes * AMDGPU_GPU_PAGE_SIZE << shift;
+                       dst += (uint64_t)nptes * AMDGPU_GPU_PAGE_SIZE << shift;
 
                        frag_start = upd_end;
                        if (frag_start >= frag_end) {
@@ -1701,8 +1696,17 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
                        }
                } while (frag_start < entry_end);
 
-               if (frag >= shift)
+               if (amdgpu_vm_pt_descendant(adev, &cursor)) {
+                       /* Mark all child entries as huge */
+                       while (cursor.pfn < frag_start) {
+                               cursor.entry->huge = true;
+                               amdgpu_vm_pt_next(adev, &cursor);
+                       }
+
+               } else if (frag >= shift) {
+                       /* or just move on to the next on the same level. */
                        amdgpu_vm_pt_next(adev, &cursor);
+               }
        }
 
        return 0;