drm/etnaviv: fix TS cache flushing on GPUs with BLT engine
authorLucas Stach <l.stach@pengutronix.de>
Wed, 26 Feb 2020 15:27:08 +0000 (16:27 +0100)
committerLucas Stach <l.stach@pengutronix.de>
Fri, 20 Mar 2020 17:40:44 +0000 (18:40 +0100)
As seen in the Vivante kernel driver, most GPUs with the BLT engine have
a broken TS cache flush. The workaround is to temporarily set the BLT
command to CLEAR_IMAGE, without actually executing the clear. Apparently
this state change is enough to trigger the required TS cache flush. As
the BLT engine is completely asychronous, we also need a few more stall
states to synchronize the flush with the frontend.

Root-caused-by: Jonathan Marek <jonathan@marek.ca>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
drivers/gpu/drm/etnaviv/etnaviv_buffer.c
drivers/gpu/drm/etnaviv/state_blt.xml.h

index 32d9fac587f9a2157d28ab3cfaee92c4505e4c68..76d38561c91031c06bd4a39fd13782695813b417 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "common.xml.h"
 #include "state.xml.h"
+#include "state_blt.xml.h"
 #include "state_hi.xml.h"
 #include "state_3d.xml.h"
 #include "cmdstream.xml.h"
@@ -233,6 +234,8 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
        struct etnaviv_cmdbuf *buffer = &gpu->buffer;
        unsigned int waitlink_offset = buffer->user_size - 16;
        u32 link_target, flush = 0;
+       bool has_blt = !!(gpu->identity.minor_features5 &
+                         chipMinorFeatures5_BLT_ENGINE);
 
        lockdep_assert_held(&gpu->lock);
 
@@ -248,16 +251,38 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
        if (flush) {
                unsigned int dwords = 7;
 
+               if (has_blt)
+                       dwords += 10;
+
                link_target = etnaviv_buffer_reserve(gpu, buffer, dwords);
 
                CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
                CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+               if (has_blt) {
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+                       CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+                       CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+               }
                CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush);
-               if (gpu->exec_state == ETNA_PIPE_3D)
-                       CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
-                                      VIVS_TS_FLUSH_CACHE_FLUSH);
+               if (gpu->exec_state == ETNA_PIPE_3D) {
+                       if (has_blt) {
+                               CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+                               CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
+                               CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+                       } else {
+                               CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
+                                              VIVS_TS_FLUSH_CACHE_FLUSH);
+                       }
+               }
                CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
                CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+               if (has_blt) {
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+                       CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+                       CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+               }
                CMD_END(buffer);
 
                etnaviv_buffer_replace_wait(buffer, waitlink_offset,
@@ -323,6 +348,8 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
        bool switch_mmu_context = gpu->mmu_context != mmu_context;
        unsigned int new_flush_seq = READ_ONCE(gpu->mmu_context->flush_seq);
        bool need_flush = switch_mmu_context || gpu->flush_seq != new_flush_seq;
+       bool has_blt = !!(gpu->identity.minor_features5 &
+                         chipMinorFeatures5_BLT_ENGINE);
 
        lockdep_assert_held(&gpu->lock);
 
@@ -433,6 +460,15 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
         * 2 semaphore stall + 1 event + 1 wait + 1 link.
         */
        return_dwords = 7;
+
+       /*
+        * When the BLT engine is present we need 6 more dwords in the return
+        * target: 3 enable/flush/disable + 4 enable/semaphore stall/disable,
+        * but we don't need the normal TS flush state.
+        */
+       if (has_blt)
+               return_dwords += 6;
+
        return_target = etnaviv_buffer_reserve(gpu, buffer, return_dwords);
        CMD_LINK(cmdbuf, return_dwords, return_target);
 
@@ -447,11 +483,25 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, u32 exec_state,
                CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE,
                                       VIVS_GL_FLUSH_CACHE_DEPTH |
                                       VIVS_GL_FLUSH_CACHE_COLOR);
-               CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
-                                      VIVS_TS_FLUSH_CACHE_FLUSH);
+               if (has_blt) {
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_SET_COMMAND, 0x1);
+                       CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+               } else {
+                       CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE,
+                                              VIVS_TS_FLUSH_CACHE_FLUSH);
+               }
        }
        CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
        CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+
+       if (has_blt) {
+               CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x1);
+               CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+               CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_BLT);
+               CMD_LOAD_STATE(buffer, VIVS_BLT_ENABLE, 0x0);
+       }
+
        CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
                       VIVS_GL_EVENT_FROM_PE);
        CMD_WAIT(buffer);
index daae55995def0114ecd419351e63abb49474ab96..0e8bcf9dcc93b8a94fdb6189b413a4638762abcc 100644 (file)
@@ -46,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
 
 /* This is a cut-down version of the state_blt.xml.h file */
 
+#define VIVS_BLT_SET_COMMAND                                   0x000140ac
+
 #define VIVS_BLT_ENABLE                                                0x000140b8
 #define VIVS_BLT_ENABLE_ENABLE                                 0x00000001