drm/v3d: Fix and extend MMU error handling.
authorEric Anholt <eric@anholt.net>
Fri, 19 Apr 2019 00:10:14 +0000 (17:10 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 16 May 2019 16:24:52 +0000 (09:24 -0700)
We were setting the wrong flags to enable PTI errors, so we were
seeing reads to invalid PTEs show up as write errors.  Also, we
weren't turning on the interrupts.  The AXI IDs we were dumping
included the outstanding write number and so they looked basically
random.  And the VIO_ADDR decoding was based on the MMU VA_WIDTH for
the first platform I worked on and was wrong on others.  In short,
this was a thorough mess from early HW enabling.

Tested on V3D 4.1 and 4.2 with intentional L2T, CLE, PTB, and TLB
faults.

Signed-off-by: Eric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20190419001014.23579-4-eric@anholt.net
Reviewed-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
drivers/gpu/drm/v3d/v3d_drv.c
drivers/gpu/drm/v3d/v3d_drv.h
drivers/gpu/drm/v3d/v3d_irq.c
drivers/gpu/drm/v3d/v3d_mmu.c
drivers/gpu/drm/v3d/v3d_regs.h

index 747fb6205ba82bb5d1d10df1e0c7f6c79894d26d..fea597f4db8acbdd1178e77825682357517a2cbb 100644 (file)
@@ -261,6 +261,7 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
        mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
        dev->coherent_dma_mask =
                DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
+       v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
 
        ident1 = V3D_READ(V3D_HUB_IDENT1);
        v3d->ver = (V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER) * 10 +
index 47b86a25629eb4d971bcbcf125e92a4a4177d392..9aad9da1eb114fbe95fe9fdee5679c5a26c086b7 100644 (file)
@@ -57,6 +57,8 @@ struct v3d_dev {
         */
        void *mmu_scratch;
        dma_addr_t mmu_scratch_paddr;
+       /* virtual address bits from V3D to the MMU. */
+       int va_width;
 
        /* Number of V3D cores. */
        u32 cores;
index fac3c542860b33c904a6999b1216919aa3f4a646..268d8a889ac5b9bc9601cb47d2b69cc1f18a3ca8 100644 (file)
@@ -162,10 +162,33 @@ v3d_hub_irq(int irq, void *arg)
                      V3D_HUB_INT_MMU_PTI |
                      V3D_HUB_INT_MMU_CAP)) {
                u32 axi_id = V3D_READ(V3D_MMU_VIO_ID);
-               u64 vio_addr = (u64)V3D_READ(V3D_MMU_VIO_ADDR) << 8;
-
-               dev_err(v3d->dev, "MMU error from client %d at 0x%08llx%s%s%s\n",
-                       axi_id, (long long)vio_addr,
+               u64 vio_addr = ((u64)V3D_READ(V3D_MMU_VIO_ADDR) <<
+                               (v3d->va_width - 32));
+               static const char *const v3d41_axi_ids[] = {
+                       "L2T",
+                       "PTB",
+                       "PSE",
+                       "TLB",
+                       "CLE",
+                       "TFU",
+                       "MMU",
+                       "GMP",
+               };
+               const char *client = "?";
+
+               V3D_WRITE(V3D_MMU_CTL,
+                         V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED |
+                                                  V3D_MMU_CTL_PT_INVALID |
+                                                  V3D_MMU_CTL_WRITE_VIOLATION));
+
+               if (v3d->ver >= 41) {
+                       axi_id = axi_id >> 5;
+                       if (axi_id < ARRAY_SIZE(v3d41_axi_ids))
+                               client = v3d41_axi_ids[axi_id];
+               }
+
+               dev_err(v3d->dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n",
+                       client, axi_id, (long long)vio_addr,
                        ((intsts & V3D_HUB_INT_MMU_WRV) ?
                         ", write violation" : ""),
                        ((intsts & V3D_HUB_INT_MMU_PTI) ?
index 7a21f1787ab1a836e1d70cebb008644a8037edca..395e81d97163211196dc8d9a5ef7817e8999a9fd 100644 (file)
@@ -69,10 +69,13 @@ int v3d_mmu_set_page_table(struct v3d_dev *v3d)
        V3D_WRITE(V3D_MMU_PT_PA_BASE, v3d->pt_paddr >> V3D_MMU_PAGE_SHIFT);
        V3D_WRITE(V3D_MMU_CTL,
                  V3D_MMU_CTL_ENABLE |
-                 V3D_MMU_CTL_PT_INVALID |
+                 V3D_MMU_CTL_PT_INVALID_ENABLE |
                  V3D_MMU_CTL_PT_INVALID_ABORT |
+                 V3D_MMU_CTL_PT_INVALID_INT |
                  V3D_MMU_CTL_WRITE_VIOLATION_ABORT |
-                 V3D_MMU_CTL_CAP_EXCEEDED_ABORT);
+                 V3D_MMU_CTL_WRITE_VIOLATION_INT |
+                 V3D_MMU_CTL_CAP_EXCEEDED_ABORT |
+                 V3D_MMU_CTL_CAP_EXCEEDED_INT);
        V3D_WRITE(V3D_MMU_ILLEGAL_ADDR,
                  (v3d->mmu_scratch_paddr >> V3D_MMU_PAGE_SHIFT) |
                  V3D_MMU_ILLEGAL_ADDR_ENABLE);
index eda1e289976f46a7ca8a10e59938183ee30fa4c9..9bcb57781d313f9b923d7594a7fff6cbfb92a2b6 100644 (file)
 # define V3D_MMU_CTL_PT_INVALID_ABORT                  BIT(19)
 # define V3D_MMU_CTL_PT_INVALID_INT                    BIT(18)
 # define V3D_MMU_CTL_PT_INVALID_EXCEPTION              BIT(17)
-# define V3D_MMU_CTL_WRITE_VIOLATION                   BIT(16)
+# define V3D_MMU_CTL_PT_INVALID_ENABLE                 BIT(16)
+# define V3D_MMU_CTL_WRITE_VIOLATION                   BIT(12)
 # define V3D_MMU_CTL_WRITE_VIOLATION_ABORT             BIT(11)
 # define V3D_MMU_CTL_WRITE_VIOLATION_INT               BIT(10)
 # define V3D_MMU_CTL_WRITE_VIOLATION_EXCEPTION         BIT(9)