Revert "drm/qxl: simplify qxl_fence_wait"
authorAlex Constantino <dreaming.about.electric.sheep@gmail.com>
Thu, 4 Apr 2024 18:14:48 +0000 (19:14 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Apr 2024 09:19:27 +0000 (11:19 +0200)
[ Upstream commit 07ed11afb68d94eadd4ffc082b97c2331307c5ea ]

This reverts commit 5a838e5d5825c85556011478abde708251cc0776.

Changes from commit 5a838e5d5825 ("drm/qxl: simplify qxl_fence_wait") would
result in a '[TTM] Buffer eviction failed' exception whenever it reached a
timeout.
Due to a dependency to DMA_FENCE_WARN this also restores some code deleted
by commit d72277b6c37d ("dma-buf: nuke DMA_FENCE_TRACE macros v2").

Fixes: 5a838e5d5825 ("drm/qxl: simplify qxl_fence_wait")
Link: https://lore.kernel.org/regressions/ZTgydqRlK6WX_b29@eldamar.lan/
Reported-by: Timo Lindfors <timo.lindfors@iki.fi>
Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1054514
Signed-off-by: Alex Constantino <dreaming.about.electric.sheep@gmail.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20240404181448.1643-2-dreaming.about.electric.sheep@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/qxl/qxl_release.c
include/linux/dma-fence.h

index 368d26da0d6a233467cdc8ef5820ebf4b7ddb964..9febc8b73f09efaaaac9d6fb8d2776f2148aed89 100644 (file)
@@ -58,16 +58,56 @@ static long qxl_fence_wait(struct dma_fence *fence, bool intr,
                           signed long timeout)
 {
        struct qxl_device *qdev;
+       struct qxl_release *release;
+       int count = 0, sc = 0;
+       bool have_drawable_releases;
        unsigned long cur, end = jiffies + timeout;
 
        qdev = container_of(fence->lock, struct qxl_device, release_lock);
+       release = container_of(fence, struct qxl_release, base);
+       have_drawable_releases = release->type == QXL_RELEASE_DRAWABLE;
 
-       if (!wait_event_timeout(qdev->release_event,
-                               (dma_fence_is_signaled(fence) ||
-                                (qxl_io_notify_oom(qdev), 0)),
-                               timeout))
-               return 0;
+retry:
+       sc++;
+
+       if (dma_fence_is_signaled(fence))
+               goto signaled;
+
+       qxl_io_notify_oom(qdev);
+
+       for (count = 0; count < 11; count++) {
+               if (!qxl_queue_garbage_collect(qdev, true))
+                       break;
+
+               if (dma_fence_is_signaled(fence))
+                       goto signaled;
+       }
+
+       if (dma_fence_is_signaled(fence))
+               goto signaled;
+
+       if (have_drawable_releases || sc < 4) {
+               if (sc > 2)
+                       /* back off */
+                       usleep_range(500, 1000);
+
+               if (time_after(jiffies, end))
+                       return 0;
+
+               if (have_drawable_releases && sc > 300) {
+                       DMA_FENCE_WARN(fence,
+                                      "failed to wait on release %llu after spincount %d\n",
+                                      fence->context & ~0xf0000000, sc);
+                       goto signaled;
+               }
+               goto retry;
+       }
+       /*
+        * yeah, original sync_obj_wait gave up after 3 spins when
+        * have_drawable_releases is not set.
+        */
 
+signaled:
        cur = jiffies;
        if (time_after(cur, end))
                return 0;
index b3772edca2e6e0ac742e5d41bd9b2fad6fba1647..fd4a823ce3cdb6f6eb4a873a1cc568c5c949e9df 100644 (file)
@@ -681,4 +681,11 @@ static inline bool dma_fence_is_container(struct dma_fence *fence)
        return dma_fence_is_array(fence) || dma_fence_is_chain(fence);
 }
 
+#define DMA_FENCE_WARN(f, fmt, args...) \
+       do {                                                            \
+               struct dma_fence *__ff = (f);                           \
+               pr_warn("f %llu#%llu: " fmt, __ff->context, __ff->seqno,\
+                        ##args);                                       \
+       } while (0)
+
 #endif /* __LINUX_DMA_FENCE_H */