With limited VRAM available, fragmentation can lead to OOM errors.
Alternating between bottom-up and top-down placement keeps BOs near the
ends of the VRAM and the available pages consecutively near the middle.

A real-world example with 16 MiB of VRAM is shown below.

  > cat /sys/kernel/debug/dri/0/vram-mm
  0x0000000000000000-0x000000000000057f: 1407: free
  0x000000000000057f-0x0000000000000b5b: 1500: used
  0x0000000000000b5b-0x0000000000000ff0: 1173: free

The first free area was the location of the fbdev framebuffer. The used
area is Weston's current framebuffer of 1500 pages. Weston now cannot
do a pageflip to another 1500 page-wide framebuffer, even though enough
pages are available. The patch resolves this problem to

  > cat /sys/kernel/debug/dri/0/vram-mm
  0x0000000000000000-0x00000000000005dc: 1500: used
  0x00000000000005dc-0x0000000000000a14: 1080: free
  0x0000000000000a14-0x0000000000000ff0: 1500: used

with both of Weston's framebuffers located near the ends of the VRAM
memory.

Signed-off-by: Thomas Zimmermann <tzimmerm...@suse.de>
---
 drivers/gpu/drm/drm_gem_vram_helper.c | 28 ++++++++++++++++++++++-----
 include/drm/drm_gem_vram_helper.h     | 10 ++++++----
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c 
b/drivers/gpu/drm/drm_gem_vram_helper.c
index 5d5bfb38bbed4..2d0b7474288de 100644
--- a/drivers/gpu/drm/drm_gem_vram_helper.c
+++ b/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -146,15 +146,33 @@ static void drm_gem_vram_placement(struct 
drm_gem_vram_object *gbo,
        unsigned int i;
        unsigned int c = 0;
        u32 invariant_flags = pl_flag & TTM_PL_FLAG_TOPDOWN;
+       struct drm_device *dev = gbo->bo.base.dev;
+       struct drm_vram_mm *vmm = dev->vram_mm;
 
        gbo->placement.placement = gbo->placements;
        gbo->placement.busy_placement = gbo->placements;
 
-       if (pl_flag & TTM_PL_FLAG_VRAM)
-               gbo->placements[c++].flags = TTM_PL_FLAG_WC |
-                                            TTM_PL_FLAG_UNCACHED |
-                                            TTM_PL_FLAG_VRAM |
-                                            invariant_flags;
+       if (pl_flag & TTM_PL_FLAG_VRAM) {
+               /*
+                * We usually have at most 2 pinned BOs during pageflips,
+                * plus cursor BOs. Even with a significant number of free
+                ' pages, always placing bottom-up can lead to fragmentation
+                * and OOM situations. So if there's no explicit request for
+                * top-down placement, we alternatingly place BOs bottom-up
+                * and top-down. The placement strategy should help to keep
+                * free VRAM pages available near the middle of the VRAM.
+                */
+               gbo->placements[c].flags = TTM_PL_FLAG_WC |
+                                          TTM_PL_FLAG_UNCACHED |
+                                          TTM_PL_FLAG_VRAM |
+                                          invariant_flags;
+               if (!(invariant_flags & TTM_PL_FLAG_TOPDOWN)) {
+                       if (vmm->place_topdown)
+                               gbo->placements[c].flags |= TTM_PL_FLAG_TOPDOWN;
+                       vmm->place_topdown = !vmm->place_topdown;
+               }
+               ++c;
+       }
 
        if (pl_flag & TTM_PL_FLAG_SYSTEM)
                gbo->placements[c++].flags = TTM_PL_MASK_CACHING |
diff --git a/include/drm/drm_gem_vram_helper.h 
b/include/drm/drm_gem_vram_helper.h
index b63bcd1b996da..04767d0ff23a6 100644
--- a/include/drm/drm_gem_vram_helper.h
+++ b/include/drm/drm_gem_vram_helper.h
@@ -165,10 +165,10 @@ void drm_gem_vram_simple_display_pipe_cleanup_fb(
 
 /**
  * struct drm_vram_mm - An instance of VRAM MM
- * @vram_base: Base address of the managed video memory
- * @vram_size: Size of the managed video memory in bytes
- * @bdev:      The TTM BO device.
- * @funcs:     TTM BO functions
+ * @vram_base:         Base address of the managed video memory
+ * @vram_size:         Size of the managed video memory in bytes
+ * @bdev:              The TTM BO device
+ * @place_topdown:     Flags the next BO to be placed at the VRAM's high end
  *
  * The fields &struct drm_vram_mm.vram_base and
  * &struct drm_vram_mm.vrm_size are managed by VRAM MM, but are
@@ -180,6 +180,8 @@ struct drm_vram_mm {
        size_t vram_size;
 
        struct ttm_bo_device bdev;
+
+       bool place_topdown;
 };
 
 /**
-- 
2.26.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to