When VRAM is nearly full, the Buddy allocator makes tradeoffs
and it may place BOs in a way that they cross 256M segments.

Move the BO to GTT when this eventuality is detected.

Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4800
Signed-off-by: Timur Kristóf <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c |  3 ++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 21 +++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index a106c7e77e26..fb49bd53bd00 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -977,6 +977,7 @@ u32 amdgpu_ttm_fill_gart_256M_placements(struct 
ttm_buffer_object *bo,
                                         u32 max_placements)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
+       const u64 sz = adev->gmc.gart_size;
        u32 i;
 
        /* Fill the placements array with 256M segments, starting from highest. 
*/
@@ -984,7 +985,7 @@ u32 amdgpu_ttm_fill_gart_256M_placements(struct 
ttm_buffer_object *bo,
                if (i * SZ_256M >= adev->gmc.gart_size)
                        break;
 
-               placements[i].lpfn = (adev->gmc.gart_size - i * SZ_256M) >> 
PAGE_SHIFT;
+               placements[i].lpfn = MIN(ALIGN(sz, SZ_256M) - i * SZ_256M, sz) 
>> PAGE_SHIFT;
                placements[i].fpfn = ALIGN_DOWN(placements[i].lpfn - 1, SZ_256M 
>> PAGE_SHIFT);
                placements[i].mem_type = TTM_PL_TT;
                placements[i].flags = bo->resource->placement;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index 993957927782..53f810c2a5fb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -617,6 +617,27 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx 
*ctx)
                        amdgpu_uvd_force_into_uvd_segment(bo);
 
                r = ttm_bo_validate(&bo->tbo, &bo->placement, &tctx);
+               if (r)
+                       return r;
+
+               /* Check if the BO placement crosses a 256M segment. */
+               if ((amdgpu_bo_gpu_offset(bo) >> 28) !=
+                   ((amdgpu_bo_gpu_offset(bo) + amdgpu_bo_size(bo)) >> 28)) {
+                       /* There is not enough memory for correct placement of 
FB/MSG BOs. */
+                       if (cmd == 0x0 || cmd == 0x3)
+                               return -ENOMEM;
+
+                       /* GTT->GTT moves are not implemented yet. */
+                       if (bo->tbo.resource->mem_type != TTM_PL_VRAM)
+                               return -ENOMEM;
+
+                       /* Try to move the BO from VRAM to GART into a 256M 
segment. */
+                       amdgpu_ttm_fill_gart_256M_placements(&bo->tbo,
+                                                            bo->placements,
+                                                            
ARRAY_SIZE(bo->placements));
+
+                       r = ttm_bo_validate(&bo->tbo, &bo->placement, &tctx);
+               }
        }
 
        return r;
-- 
2.54.0

Reply via email to