drm/panthor: flush FW AS caches in slow reset path
authorAdrián Larumbe <adrian.larumbe@collabora.com>
Mon, 2 Sep 2024 13:02:35 +0000 (14:02 +0100)
committerBoris Brezillon <boris.brezillon@collabora.com>
Thu, 5 Sep 2024 07:45:33 +0000 (09:45 +0200)
In the off-chance that waiting for the firmware to signal its booted status
timed out in the fast reset path, one must flush the cache lines for the
entire FW VM address space before reloading the regions, otherwise stale
values eventually lead to a scheduler job timeout.

Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block")
Cc: stable@vger.kernel.org
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Acked-by: Liviu Dudau <liviu.dudau@arm.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240902130237.3440720-1-adrian.larumbe@collabora.com
drivers/gpu/drm/panthor/panthor_fw.c
drivers/gpu/drm/panthor/panthor_mmu.c
drivers/gpu/drm/panthor/panthor_mmu.h

index 857f3f11258aad3ec659a6111d834ef3c177ff12..ef232c0c204932c9b3e5f25841131c48dd566a98 100644 (file)
@@ -1089,6 +1089,12 @@ int panthor_fw_post_reset(struct panthor_device *ptdev)
                panthor_fw_stop(ptdev);
                ptdev->fw->fast_reset = false;
                drm_err(&ptdev->base, "FW fast reset failed, trying a slow reset");
+
+               ret = panthor_vm_flush_all(ptdev->fw->vm);
+               if (ret) {
+                       drm_err(&ptdev->base, "FW slow reset failed (couldn't flush FW's AS l2cache)");
+                       return ret;
+               }
        }
 
        /* Reload all sections, including RO ones. We're not supposed
@@ -1099,7 +1105,7 @@ int panthor_fw_post_reset(struct panthor_device *ptdev)
 
        ret = panthor_fw_start(ptdev);
        if (ret) {
-               drm_err(&ptdev->base, "FW slow reset failed");
+               drm_err(&ptdev->base, "FW slow reset failed (couldn't start the FW )");
                return ret;
        }
 
index fa0a002b1016ec0f1a9e71edd4ccd8a8209e0bff..cc6e13a9778358b7c5eee224ef50c06e5972c85b 100644 (file)
@@ -576,6 +576,12 @@ static int mmu_hw_do_operation_locked(struct panthor_device *ptdev, int as_nr,
        if (as_nr < 0)
                return 0;
 
+       /*
+        * If the AS number is greater than zero, then we can be sure
+        * the device is up and running, so we don't need to explicitly
+        * power it up
+        */
+
        if (op != AS_COMMAND_UNLOCK)
                lock_region(ptdev, as_nr, iova, size);
 
@@ -874,14 +880,23 @@ static int panthor_vm_flush_range(struct panthor_vm *vm, u64 iova, u64 size)
        if (!drm_dev_enter(&ptdev->base, &cookie))
                return 0;
 
-       /* Flush the PTs only if we're already awake */
-       if (pm_runtime_active(ptdev->base.dev))
-               ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT);
+       ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT);
 
        drm_dev_exit(cookie);
        return ret;
 }
 
+/**
+ * panthor_vm_flush_all() - Flush L2 caches for the entirety of a VM's AS
+ * @vm: VM whose cache to flush
+ *
+ * Return: 0 on success, a negative error code if flush failed.
+ */
+int panthor_vm_flush_all(struct panthor_vm *vm)
+{
+       return panthor_vm_flush_range(vm, vm->base.mm_start, vm->base.mm_range);
+}
+
 static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size)
 {
        struct panthor_device *ptdev = vm->ptdev;
index f3c1ed19f973f6c6f44e6f431cc604de5ba79adb..6788771071e35557ccde471301bf4aa2ef32ec8f 100644 (file)
@@ -31,6 +31,7 @@ panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 va, u64 *bo_offset);
 int panthor_vm_active(struct panthor_vm *vm);
 void panthor_vm_idle(struct panthor_vm *vm);
 int panthor_vm_as(struct panthor_vm *vm);
+int panthor_vm_flush_all(struct panthor_vm *vm);
 
 struct panthor_heap_pool *
 panthor_vm_get_heap_pool(struct panthor_vm *vm, bool create);