diff mbox series

[RFC,11/16] drm/ttm: Add a simple api to set / clear purgeable ttm_tt content

Message ID 20230215161405.187368-12-thomas.hellstrom@linux.intel.com (mailing list archive)
State New
Headers show
Series Add a TTM shrinker | expand

Commit Message

Thomas Hellstrom Feb. 15, 2023, 4:14 p.m. UTC
In the absence of free swap space, a shrinker could still efficiently
free memory the content of which is no longer needed, and graphics
drivers typically has an interface to mark buffer object content as
no longer needed.

Add a possibility to propagate this to TTM, so that the shrinker
accounting and shrinker actions can be updated accordingly.

Moving forward, we will probably want this interface on the bo level and
have bo move support for it, but for now we strictly only need it for
the shrinker. Another option would be to have the drivers do the
purgeable vs shrinkable accounting.

This still leaves the responsibility to the driver to assign proper
LRU priority to purgeable buffer object so that the shrinker finds those
objects early during LRU traversal.

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
 drivers/gpu/drm/ttm/ttm_tt.c | 59 ++++++++++++++++++++++++++++++++++++
 include/drm/ttm/ttm_tt.h     |  3 ++
 2 files changed, 62 insertions(+)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index a39c617c7a8e..c63be8f5ed2a 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -105,6 +105,65 @@  void ttm_tt_set_unpinned(const struct ttm_device *bdev, const struct ttm_tt *tt)
 		ttm_tt_mod_shrinkable_pages(tt->num_pages, 0);
 }
 
+/**
+ * ttm_tt_set_dontneed() - Mark ttm_tt content as not needed.
+ * @bdev: The ttm device.
+ * @tt: The struct ttm_tt.
+ *
+ * Mark the ttm_tt content as not needed for the shrinker accounting.
+ * This also means that the content will not be backed up on shrinking,
+ * but rather freed immediately.
+ *
+ * Return: 0 if successful, -EALREADY if content was never present or
+ * already backed up and was purged by this call.
+ */
+int ttm_tt_set_dontneed(const struct ttm_device *bdev, struct ttm_tt *tt)
+{
+	if (ttm_tt_is_populated(tt)) {
+		if (!ttm_tt_purgeable(tt)) {
+			tt->page_flags |= TTM_TT_FLAG_DONTNEED;
+			if (ttm_tt_shrinkable(bdev, tt))
+				ttm_tt_mod_shrinkable_pages(-(long)tt->num_pages,
+							    tt->num_pages);
+		}
+		return 0;
+	}
+
+	if (tt->swap_storage)
+		fput(tt->swap_storage);
+	tt->swap_storage = NULL;
+
+	return -EALREADY;
+}
+EXPORT_SYMBOL(ttm_tt_set_dontneed);
+
+/**
+ * ttm_tt_set_willneed() - Mark tt_tt content as needed.
+ * @bdev: The ttm device.
+ * @tt: The struct ttm_tt.
+ *
+ * Mark the ttm_tt content as needed and update the shrinker accounting
+ * accordingly.
+ *
+ * Return: 0 if successful, -EALREADY if content was never present or
+ * was already purged.
+ */
+int ttm_tt_set_willneed(const struct ttm_device *bdev, struct ttm_tt *tt)
+{
+	if (ttm_tt_is_populated(tt)) {
+		if (ttm_tt_purgeable(tt)) {
+			tt->page_flags &= ~TTM_TT_FLAG_DONTNEED;
+			if (ttm_tt_shrinkable(bdev, tt))
+				ttm_tt_mod_shrinkable_pages(tt->num_pages,
+							    -(long)tt->num_pages);
+		}
+		return 0;
+	}
+
+	return -EALREADY;
+}
+EXPORT_SYMBOL(ttm_tt_set_willneed);
+
 /*
  * Allocates a ttm structure for the given BO.
  */
diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h
index 69467671c2dd..abb17527f76c 100644
--- a/include/drm/ttm/ttm_tt.h
+++ b/include/drm/ttm/ttm_tt.h
@@ -241,6 +241,9 @@  static inline bool ttm_tt_purgeable(struct ttm_tt *tt)
 void ttm_tt_set_pinned(const struct ttm_device *bdev, const struct ttm_tt *tt);
 
 void ttm_tt_set_unpinned(const struct ttm_device *bdev, const struct ttm_tt *tt);
+int ttm_tt_set_dontneed(const struct ttm_device *bdev, struct ttm_tt *tt);
+
+int ttm_tt_set_willneed(const struct ttm_device *bdev, struct ttm_tt *tt);
 
 #if IS_ENABLED(CONFIG_AGP)
 #include <linux/agp_backend.h>