Mesa (main): v3d/simulator: capture hub interrupts

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jun 1 10:39:55 UTC 2021


Module: Mesa
Branch: main
Commit: 123c7d7277817287fdce97092678bdc4136bfbb5
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=123c7d7277817287fdce97092678bdc4136bfbb5

Author: Alejandro Piñeiro <apinheiro at igalia.com>
Date:   Sat May  8 01:11:42 2021 +0200

v3d/simulator: capture hub interrupts

So far we were not capturing any HUB interrupt, just core. This could
be a problem if any is fired, as we could enter on an infinite
loop. With this commit we start to capture them. So we split v3d_isr
into core and hub interrupt handling.

As reference we capture the same HUB interrupts that we capture on the
v3d kernel support.

It is worth to note that all those are mostly untested. Now with both
opengl/vulkan driver being stable we were not able to raise those
interrupts.

v2 (Juan feedback):
   * Just one V3D_VERSION >= 41 block, more readable
   * Assert that the core is 0 at v3d_isr_core (we don't handle
     multi-core right now).

Reviewed-by: Juan A. Suarez <jasuarez at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11039>

---

 src/broadcom/simulator/v3d_simulator_wrapper.cpp |   5 +
 src/broadcom/simulator/v3d_simulator_wrapper.h   |   1 +
 src/broadcom/simulator/v3dx_simulator.c          | 161 +++++++++++++++++++----
 3 files changed, 141 insertions(+), 26 deletions(-)

diff --git a/src/broadcom/simulator/v3d_simulator_wrapper.cpp b/src/broadcom/simulator/v3d_simulator_wrapper.cpp
index 15db767d534..ffd8e463ade 100644
--- a/src/broadcom/simulator/v3d_simulator_wrapper.cpp
+++ b/src/broadcom/simulator/v3d_simulator_wrapper.cpp
@@ -89,5 +89,10 @@ v3d_hw_set_isr(struct v3d_hw *hw, void (*isr)(uint32_t status))
         hw->set_isr(isr);
 }
 
+uint32_t v3d_hw_get_hub_core()
+{
+        return V3D_HW_HUB_CORE;
+}
+
 }
 #endif /* USE_V3D_SIMULATOR */
diff --git a/src/broadcom/simulator/v3d_simulator_wrapper.h b/src/broadcom/simulator/v3d_simulator_wrapper.h
index b20ea2484b4..c6383104f3f 100644
--- a/src/broadcom/simulator/v3d_simulator_wrapper.h
+++ b/src/broadcom/simulator/v3d_simulator_wrapper.h
@@ -39,6 +39,7 @@ void v3d_hw_write_reg(struct v3d_hw *hw, uint32_t reg, uint32_t val);
 void v3d_hw_tick(struct v3d_hw *hw);
 int v3d_hw_get_version(struct v3d_hw *hw);
 void v3d_hw_set_isr(struct v3d_hw *hw, void (*isr)(uint32_t status));
+uint32_t v3d_hw_get_hub_core();
 
 #ifdef __cplusplus
 }
diff --git a/src/broadcom/simulator/v3dx_simulator.c b/src/broadcom/simulator/v3dx_simulator.c
index 15772085a27..2766f245adc 100644
--- a/src/broadcom/simulator/v3dx_simulator.c
+++ b/src/broadcom/simulator/v3dx_simulator.c
@@ -41,6 +41,7 @@
 #include "v3d_simulator_wrapper.h"
 
 #include "util/macros.h"
+#include "util/bitscan.h"
 #include "drm-uapi/v3d_drm.h"
 
 #define HW_REGISTER_RO(x) (x)
@@ -248,37 +249,132 @@ v3dX(simulator_get_param_ioctl)(struct v3d_hw *v3d,
 
 static struct v3d_hw *v3d_isr_hw;
 
+
+static void
+v3d_isr_core(struct v3d_hw *v3d,
+             unsigned core)
+{
+        /* FIXME: so far we are assuming just one core, and using only the _0_
+         * registers. If we add multiple-core on the simulator, we would need
+         * to pass core as a parameter, and chose the proper registers.
+         */
+        assert(core == 0);
+        uint32_t core_status = V3D_READ(V3D_CTL_0_INT_STS);
+        V3D_WRITE(V3D_CTL_0_INT_CLR, core_status);
+
+        if (core_status & V3D_CTL_0_INT_STS_INT_OUTOMEM_SET) {
+                uint32_t size = 256 * 1024;
+                uint32_t offset = v3d_simulator_get_spill(size);
+
+                v3d_reload_gmp(v3d);
+
+                V3D_WRITE(V3D_PTB_0_BPOA, offset);
+                V3D_WRITE(V3D_PTB_0_BPOS, size);
+                return;
+        }
+
+        if (core_status & V3D_CTL_0_INT_STS_INT_GMPV_SET) {
+                fprintf(stderr, "GMP violation at 0x%08x\n",
+                        V3D_READ(V3D_GMP_VIO_ADDR));
+                abort();
+        } else {
+                fprintf(stderr,
+                        "Unexpected ISR with core status 0x%08x\n",
+                        core_status);
+        }
+        abort();
+}
+
+static void
+handle_mmu_interruptions(struct v3d_hw *v3d,
+                         uint32_t hub_status)
+{
+        bool wrv = hub_status & V3D_HUB_CTL_INT_STS_INT_MMU_WRV_SET;
+        bool pti = hub_status & V3D_HUB_CTL_INT_STS_INT_MMU_PTI_SET;
+        bool cap = hub_status & V3D_HUB_CTL_INT_STS_INT_MMU_CAP_SET;
+
+        if (!(pti || cap || wrv))
+                return;
+
+        const char *client = "?";
+        uint32_t axi_id = V3D_READ(V3D_MMU_VIO_ID);
+        uint32_t va_width = 30;
+
+#if V3D_VERSION >= 41
+        static const char *const v3d41_axi_ids[] = {
+                "L2T",
+                "PTB",
+                "PSE",
+                "TLB",
+                "CLE",
+                "TFU",
+                "MMU",
+                "GMP",
+        };
+
+        axi_id = axi_id >> 5;
+        if (axi_id < ARRAY_SIZE(v3d41_axi_ids))
+                client = v3d41_axi_ids[axi_id];
+
+        uint32_t mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
+
+        va_width += ((mmu_debug & V3D_MMU_DEBUG_INFO_VA_WIDTH_SET)
+                     >> V3D_MMU_DEBUG_INFO_VA_WIDTH_LSB);
+#endif
+        /* Only the top bits (final number depends on the gen) of the virtual
+         * address are reported in the MMU VIO_ADDR register.
+         */
+        uint64_t vio_addr = ((uint64_t)V3D_READ(V3D_MMU_VIO_ADDR) <<
+                             (va_width - 32));
+
+        /* Difference with the kernal: here were are going to abort after
+         * logging, so we don't bother with some stuff that the kernel does,
+         * like restoring the MMU ctrl bits
+         */
+
+        fprintf(stderr, "MMU error from client %s (%d) at 0x%llx%s%s%s\n",
+                client, axi_id, (long long) vio_addr,
+                wrv ? ", write violation" : "",
+                pti ? ", pte invalid" : "",
+                cap ? ", cap exceeded" : "");
+
+        abort();
+}
+
+static void
+v3d_isr_hub(struct v3d_hw *v3d)
+{
+        uint32_t hub_status = V3D_READ(V3D_HUB_CTL_INT_STS);
+
+        /* Acknowledge the interrupts we're handling here */
+        V3D_WRITE(V3D_HUB_CTL_INT_CLR, hub_status);
+
+        if (hub_status & V3D_HUB_CTL_INT_STS_INT_TFUC_SET) {
+                /* FIXME: we were not able to raise this exception. We let the
+                 * unreachable here, so we could get one if it is raised on
+                 * the future. In any case, note that for this case we would
+                 * only be doing debugging log.
+                 */
+                unreachable("TFU Conversion Complete interrupt not handled");
+        }
+
+        handle_mmu_interruptions(v3d, hub_status);
+}
+
 static void
 v3d_isr(uint32_t hub_status)
 {
         struct v3d_hw *v3d = v3d_isr_hw;
+        uint32_t mask = hub_status;
 
-        /* Check the per-core bits */
-        if (hub_status & (1 << 0)) {
-                uint32_t core_status = V3D_READ(V3D_CTL_0_INT_STS);
-                V3D_WRITE(V3D_CTL_0_INT_CLR, core_status);
-
-                if (core_status & V3D_CTL_0_INT_STS_INT_OUTOMEM_SET) {
-                        uint32_t size = 256 * 1024;
-                        uint32_t offset = v3d_simulator_get_spill(size);
-
-                        v3d_reload_gmp(v3d);
-
-                        V3D_WRITE(V3D_PTB_0_BPOA, offset);
-                        V3D_WRITE(V3D_PTB_0_BPOS, size);
-                        return;
-                }
-
-                if (core_status & V3D_CTL_0_INT_STS_INT_GMPV_SET) {
-                        fprintf(stderr, "GMP violation at 0x%08x\n",
-                                V3D_READ(V3D_GMP_VIO_ADDR));
-                        abort();
-                } else {
-                        fprintf(stderr,
-                                "Unexpected ISR with core status 0x%08x\n",
-                                core_status);
-                }
-                abort();
+        /* Check the hub_status bits */
+        while (mask) {
+                unsigned core = u_bit_scan(&mask);
+
+                if (core == v3d_hw_get_hub_core())
+                        v3d_isr_hub(v3d);
+                else
+                        v3d_isr_core(v3d, core);
         }
 
         return;
@@ -299,11 +395,24 @@ v3dX(simulator_init_regs)(struct v3d_hw *v3d)
         V3D_WRITE(V3D_CTL_0_MISCCFG, V3D_CTL_1_MISCCFG_OVRTMUOUT_SET);
 #endif
 
+        /* FIXME: the kernel captures some additional core interrupts here,
+         * for tracing. Perhaps we should evaluate to do the same here and add
+         * some debug options.
+         */
         uint32_t core_interrupts = (V3D_CTL_0_INT_STS_INT_GMPV_SET |
                                     V3D_CTL_0_INT_STS_INT_OUTOMEM_SET);
         V3D_WRITE(V3D_CTL_0_INT_MSK_SET, ~core_interrupts);
         V3D_WRITE(V3D_CTL_0_INT_MSK_CLR, core_interrupts);
 
+        uint32_t hub_interrupts =
+           (V3D_HUB_CTL_INT_STS_INT_MMU_WRV_SET |  /* write violation */
+            V3D_HUB_CTL_INT_STS_INT_MMU_PTI_SET |  /* page table invalid */
+            V3D_HUB_CTL_INT_STS_INT_MMU_CAP_SET |  /* CAP exceeded */
+            V3D_HUB_CTL_INT_STS_INT_TFUC_SET); /* TFU conversion */
+
+        V3D_WRITE(V3D_HUB_CTL_INT_MSK_SET, ~hub_interrupts);
+        V3D_WRITE(V3D_HUB_CTL_INT_MSK_CLR, hub_interrupts);
+
         v3d_isr_hw = v3d;
         v3d_hw_set_isr(v3d, v3d_isr);
 }



More information about the mesa-commit mailing list