accel/ivpu: Clear specific interrupt status bits on C0
authorKarol Wachowski <karol.wachowski@linux.intel.com>
Mon, 3 Jul 2023 08:07:25 +0000 (10:07 +0200)
committerStanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Wed, 5 Jul 2023 10:29:39 +0000 (12:29 +0200)
MTL C0 stepping fixed issue related to butrress interrupt status clearing,
to clear an interrupt status it is required to write 1 to specific
status bit field. This allows to execute read, modify and write routine.

Writing 0 will not clear the interrupt and will cause interrupt storm.

Fixes: 35b137630f08 ("accel/ivpu: Introduce a new DRM driver for Intel VPU")
Cc: stable@vger.kernel.org # 6.3.x
Signed-off-by: Karol Wachowski <karol.wachowski@linux.intel.com>
Reviewed-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230703080725.2065635-2-stanislaw.gruszka@linux.intel.com
drivers/accel/ivpu/ivpu_drv.h
drivers/accel/ivpu/ivpu_hw_mtl.c

index d3013fb..399dc5d 100644 (file)
@@ -75,6 +75,7 @@ struct ivpu_wa_table {
        bool punit_disabled;
        bool clear_runtime_mem;
        bool d3hot_after_power_off;
+       bool interrupt_clear_with_0;
 };
 
 struct ivpu_hw_info;
index 3485be2..2a5dd3a 100644 (file)
@@ -101,6 +101,9 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev)
        vdev->wa.punit_disabled = ivpu_is_fpga(vdev);
        vdev->wa.clear_runtime_mem = false;
        vdev->wa.d3hot_after_power_off = true;
+
+       if (ivpu_device_id(vdev) == PCI_DEVICE_ID_MTL && ivpu_revision(vdev) < 4)
+               vdev->wa.interrupt_clear_with_0 = true;
 }
 
 static void ivpu_hw_timeouts_init(struct ivpu_device *vdev)
@@ -973,12 +976,15 @@ static u32 ivpu_hw_mtl_irqb_handler(struct ivpu_device *vdev, int irq)
                schedule_recovery = true;
        }
 
-       /*
-        * Clear local interrupt status by writing 0 to all bits.
-        * This must be done after interrupts are cleared at the source.
-        * Writing 1 triggers an interrupt, so we can't perform read update write.
-        */
-       REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, 0x0);
+       /* This must be done after interrupts are cleared at the source. */
+       if (IVPU_WA(interrupt_clear_with_0))
+               /*
+                * Writing 1 triggers an interrupt, so we can't perform read update write.
+                * Clear local interrupt status by writing 0 to all bits.
+                */
+               REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, 0x0);
+       else
+               REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, status);
 
        /* Re-enable global interrupt */
        REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x0);