]> www.infradead.org Git - users/willy/linux.git/commitdiff
drm/msm: Support evicting GEM objects to swap
authorRob Clark <robdclark@chromium.org>
Mon, 5 Apr 2021 17:45:31 +0000 (10:45 -0700)
committerRob Clark <robdclark@chromium.org>
Wed, 7 Apr 2021 18:05:48 +0000 (11:05 -0700)
Now that tracking is wired up for potentially evictable GEM objects,
wire up shrinker and the remaining GEM bits for unpinning backing pages
of inactive objects.

Disabled by default for now, with an 'enable_eviction' module param to
enable so that we can get some more testing on the range of generations
(and iommu pairings) supported.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Link: https://lore.kernel.org/r/20210405174532.1441497-9-robdclark@gmail.com
Signed-off-by: Rob Clark <robdclark@chromium.org>
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_shrinker.c
drivers/gpu/drm/msm/msm_gpu_trace.h

index f0cd8b9c189beaa35d991440075f5fd73c8be96c..b199942266a26502eb449e83010d01a9cbc41bf1 100644 (file)
@@ -759,6 +759,29 @@ void msm_gem_purge(struct drm_gem_object *obj)
                        0, (loff_t)-1);
 }
 
+/**
+ * Unpin the backing pages and make them available to be swapped out.
+ */
+void msm_gem_evict(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+       GEM_WARN_ON(!msm_gem_is_locked(obj));
+       GEM_WARN_ON(is_unevictable(msm_obj));
+       GEM_WARN_ON(!msm_obj->evictable);
+       GEM_WARN_ON(msm_obj->active_count);
+
+       /* Get rid of any iommu mapping(s): */
+       put_iova_spaces(obj, false);
+
+       drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
+
+       put_pages(obj);
+
+       update_inactive(msm_obj);
+}
+
 void msm_gem_vunmap(struct drm_gem_object *obj)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
index a4d85955cbd9842676c526d79bdcbb54637ccb15..1187ecf9d6470678246b4858ee3dbfcfb1a97fff 100644 (file)
@@ -9,12 +9,29 @@
 #include "msm_gpu.h"
 #include "msm_gpu_trace.h"
 
+/* Default disabled for now until it has some more testing on the different
+ * iommu combinations that can be paired with the driver:
+ */
+bool enable_eviction = false;
+MODULE_PARM_DESC(enable_eviction, "Enable swappable GEM buffers");
+module_param(enable_eviction, bool, 0600);
+
+static bool can_swap(void)
+{
+       return enable_eviction && get_nr_swap_pages() > 0;
+}
+
 static unsigned long
 msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
 {
        struct msm_drm_private *priv =
                container_of(shrinker, struct msm_drm_private, shrinker);
-       return priv->shrinkable_count;
+       unsigned count = priv->shrinkable_count;
+
+       if (can_swap())
+               count += priv->evictable_count;
+
+       return count;
 }
 
 static bool
@@ -32,6 +49,17 @@ purge(struct msm_gem_object *msm_obj)
        return true;
 }
 
+static bool
+evict(struct msm_gem_object *msm_obj)
+{
+       if (is_unevictable(msm_obj))
+               return false;
+
+       msm_gem_evict(&msm_obj->base);
+
+       return true;
+}
+
 static unsigned long
 scan(struct msm_drm_private *priv, unsigned nr_to_scan, struct list_head *list,
                bool (*shrink)(struct msm_gem_object *msm_obj))
@@ -104,6 +132,16 @@ msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
        if (freed > 0)
                trace_msm_gem_purge(freed << PAGE_SHIFT);
 
+       if (can_swap() && freed < sc->nr_to_scan) {
+               int evicted = scan(priv, sc->nr_to_scan - freed,
+                               &priv->inactive_willneed, evict);
+
+               if (evicted > 0)
+                       trace_msm_gem_evict(evicted << PAGE_SHIFT);
+
+               freed += evicted;
+       }
+
        return (freed > 0) ? freed : SHRINK_STOP;
 }
 
index 03e0c2536b94bce56e040cdaf18d417128c54836..ca0b08d7875b7e1db71c67ec1e44c62c87e77150 100644 (file)
@@ -128,6 +128,19 @@ TRACE_EVENT(msm_gem_purge,
 );
 
 
+TRACE_EVENT(msm_gem_evict,
+               TP_PROTO(u32 bytes),
+               TP_ARGS(bytes),
+               TP_STRUCT__entry(
+                       __field(u32, bytes)
+                       ),
+               TP_fast_assign(
+                       __entry->bytes = bytes;
+                       ),
+               TP_printk("Evicting %u bytes", __entry->bytes)
+);
+
+
 TRACE_EVENT(msm_gem_purge_vmaps,
                TP_PROTO(u32 unmapped),
                TP_ARGS(unmapped),