]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/xe/gsc: do not flush the GSC worker from the reset path
authorDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Fri, 2 May 2025 15:51:04 +0000 (08:51 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 May 2025 12:31:57 +0000 (14:31 +0200)
commit 03552d8ac0afcc080c339faa0b726e2c0e9361cb upstream.

The workqueue used for the reset worker is marked as WQ_MEM_RECLAIM,
while the GSC one isn't (and can't be as we need to do memory
allocations in the gsc worker). Therefore, we can't flush the latter
from the former.

The reason why we had such a flush was to avoid interrupting either
the GSC FW load or in progress GSC proxy operations. GSC proxy
operations fall into 2 categories:

1) GSC proxy init: this only happens once immediately after GSC FW load
   and does not support being interrupted. The only way to recover from
   an interruption of the proxy init is to do an FLR and re-load the GSC.

2) GSC proxy request: this can happen in response to a request that
   the driver sends to the GSC. If this is interrupted, the GSC FW will
   timeout and the driver request will be failed, but overall the GSC
   will keep working fine.

Flushing the work allowed us to avoid interruption in both cases (unless
the hang came from the GSC engine itself, in which case we're toast
anyway). However, a failure on a proxy request is tolerable if we're in
a scenario where we're triggering a GT reset (i.e., something is already
gone pretty wrong), so what we really need to avoid is interrupting
the init flow, which we can do by polling on the register that reports
when the proxy init is complete (as that ensure us that all the load and
init operations have been completed).

Note that during suspend we still want to do a flush of the worker to
make sure it completes any operations involving the HW before the power
is cut.

v2: fix spelling in commit msg, rename waiter function (Julia)

Fixes: dd0e89e5edc2 ("drm/xe/gsc: GSC FW load")
Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/4830
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: John Harrison <John.C.Harrison@Intel.com>
Cc: Alan Previn <alan.previn.teres.alexis@intel.com>
Cc: <stable@vger.kernel.org> # v6.8+
Reviewed-by: Julia Filipchuk <julia.filipchuk@intel.com>
Link: https://lore.kernel.org/r/20250502155104.2201469-1-daniele.ceraolospurio@intel.com
(cherry picked from commit 12370bfcc4f0bdf70279ec5b570eb298963422b5)
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/xe/xe_gsc.c
drivers/gpu/drm/xe/xe_gsc.h
drivers/gpu/drm/xe/xe_gsc_proxy.c
drivers/gpu/drm/xe/xe_gsc_proxy.h
drivers/gpu/drm/xe/xe_gt.c
drivers/gpu/drm/xe/xe_uc.c
drivers/gpu/drm/xe/xe_uc.h

index 1eb791ddc375c7b5af482932dadf84692f9bdbe6..0f11b1c00960d572156632854d4fd7d5a71dedf7 100644 (file)
@@ -564,6 +564,28 @@ void xe_gsc_remove(struct xe_gsc *gsc)
        xe_gsc_proxy_remove(gsc);
 }
 
+void xe_gsc_stop_prepare(struct xe_gsc *gsc)
+{
+       struct xe_gt *gt = gsc_to_gt(gsc);
+       int ret;
+
+       if (!xe_uc_fw_is_loadable(&gsc->fw) || xe_uc_fw_is_in_error_state(&gsc->fw))
+               return;
+
+       xe_force_wake_assert_held(gt_to_fw(gt), XE_FW_GSC);
+
+       /*
+        * If the GSC FW load or the proxy init are interrupted, the only way
+        * to recover it is to do an FLR and reload the GSC from scratch.
+        * Therefore, let's wait for the init to complete before stopping
+        * operations. The proxy init is the last step, so we can just wait on
+        * that
+        */
+       ret = xe_gsc_wait_for_proxy_init_done(gsc);
+       if (ret)
+               xe_gt_err(gt, "failed to wait for GSC init completion before uc stop\n");
+}
+
 /*
  * wa_14015076503: if the GSC FW is loaded, we need to alert it before doing a
  * GSC engine reset by writing a notification bit in the GS1 register and then
index e282b9ef6ec4d5b4956bb5ffdb0ccb1d328b0d19..c31fe24c4b663c0e06ce18e0e5358cf3b502a003 100644 (file)
@@ -16,6 +16,7 @@ struct xe_hw_engine;
 int xe_gsc_init(struct xe_gsc *gsc);
 int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc);
 void xe_gsc_wait_for_worker_completion(struct xe_gsc *gsc);
+void xe_gsc_stop_prepare(struct xe_gsc *gsc);
 void xe_gsc_load_start(struct xe_gsc *gsc);
 void xe_gsc_remove(struct xe_gsc *gsc);
 void xe_gsc_hwe_irq_handler(struct xe_hw_engine *hwe, u16 intr_vec);
index 24cc6a4f9a96a2941f7cc7d6e9d2600a85b0914e..76636da3d06cb41f2ff531e9a8ec1290a9629872 100644 (file)
@@ -71,6 +71,17 @@ bool xe_gsc_proxy_init_done(struct xe_gsc *gsc)
               HECI1_FWSTS1_PROXY_STATE_NORMAL;
 }
 
+int xe_gsc_wait_for_proxy_init_done(struct xe_gsc *gsc)
+{
+       struct xe_gt *gt = gsc_to_gt(gsc);
+
+       /* Proxy init can take up to 500ms, so wait double that for safety */
+       return xe_mmio_wait32(&gt->mmio, HECI_FWSTS1(MTL_GSC_HECI1_BASE),
+                             HECI1_FWSTS1_CURRENT_STATE,
+                             HECI1_FWSTS1_PROXY_STATE_NORMAL,
+                             USEC_PER_SEC, NULL, false);
+}
+
 static void __gsc_proxy_irq_rmw(struct xe_gsc *gsc, u32 clr, u32 set)
 {
        struct xe_gt *gt = gsc_to_gt(gsc);
index c511ade6b8637839756aeb2e61bfaf85b95c0217..e2498aa6de18818936361a6afff73ba67c7a4644 100644 (file)
@@ -13,6 +13,7 @@ struct xe_gsc;
 int xe_gsc_proxy_init(struct xe_gsc *gsc);
 bool xe_gsc_proxy_init_done(struct xe_gsc *gsc);
 void xe_gsc_proxy_remove(struct xe_gsc *gsc);
+int xe_gsc_wait_for_proxy_init_done(struct xe_gsc *gsc);
 int xe_gsc_proxy_start(struct xe_gsc *gsc);
 
 int xe_gsc_proxy_request_handler(struct xe_gsc *gsc);
index 94eed1315b0f1b024933f751e13ae5f42b189451..150dca2f91033569082553d004fd7da84557b85a 100644 (file)
@@ -862,7 +862,7 @@ void xe_gt_suspend_prepare(struct xe_gt *gt)
 
        fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL);
 
-       xe_uc_stop_prepare(&gt->uc);
+       xe_uc_suspend_prepare(&gt->uc);
 
        xe_force_wake_put(gt_to_fw(gt), fw_ref);
 }
index 0d073a9987c2e8732e120049832ddba3b80caf9a..bb03c524613f2c437a0ea0b79d5d78a84ab0f904 100644 (file)
@@ -241,7 +241,7 @@ void xe_uc_gucrc_disable(struct xe_uc *uc)
 
 void xe_uc_stop_prepare(struct xe_uc *uc)
 {
-       xe_gsc_wait_for_worker_completion(&uc->gsc);
+       xe_gsc_stop_prepare(&uc->gsc);
        xe_guc_stop_prepare(&uc->guc);
 }
 
@@ -275,6 +275,12 @@ again:
                goto again;
 }
 
+void xe_uc_suspend_prepare(struct xe_uc *uc)
+{
+       xe_gsc_wait_for_worker_completion(&uc->gsc);
+       xe_guc_stop_prepare(&uc->guc);
+}
+
 int xe_uc_suspend(struct xe_uc *uc)
 {
        /* GuC submission not enabled, nothing to do */
index 506517c1133397f746d53284e3f45a72fd4935a8..ba2937ab94cf564be377daa8e99ac44d893aeca4 100644 (file)
@@ -18,6 +18,7 @@ int xe_uc_reset_prepare(struct xe_uc *uc);
 void xe_uc_stop_prepare(struct xe_uc *uc);
 void xe_uc_stop(struct xe_uc *uc);
 int xe_uc_start(struct xe_uc *uc);
+void xe_uc_suspend_prepare(struct xe_uc *uc);
 int xe_uc_suspend(struct xe_uc *uc);
 int xe_uc_sanitize_reset(struct xe_uc *uc);
 void xe_uc_remove(struct xe_uc *uc);