]> git.ipfire.org Git - thirdparty/kernel/linux.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)
committerLucas De Marchi <lucas.demarchi@intel.com>
Thu, 8 May 2025 19:44:41 +0000 (12:44 -0700)
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>
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 fd41113f857251b63161d332a8dbae449fc8aa43..0bcf97063ff61a1696700fe356911a5b0768811e 100644 (file)
@@ -555,6 +555,28 @@ void xe_gsc_wait_for_worker_completion(struct xe_gsc *gsc)
                flush_work(&gsc->work);
 }
 
+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 d99f66c38075c46435fb890e23df81996596dd69..b8b8e0810ad94af0c404bad63cf3f3fdd002a20d 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_hwe_irq_handler(struct xe_hw_engine *hwe, u16 intr_vec);
 
index 8cf70b228ff3b68370673e25c79c5a6c7c1c0426..d0519cd6704a11781b75f0efbb0d979fe6d772ad 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 fdef56995cd43ebbb919572429e3428619f508b5..765602221dbcf349de466bcda74ffd55f66bfe98 100644 (file)
@@ -12,6 +12,7 @@ struct xe_gsc;
 
 int xe_gsc_proxy_init(struct xe_gsc *gsc);
 bool xe_gsc_proxy_init_done(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 10a9e3c72b3604b0276f6e42985c9737ab36638f..66198cf2662c575b1b8f8ce6d152548628aacbdf 100644 (file)
@@ -857,7 +857,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 c14bd22820441cf2bf1a533d43a3a2cd51a27f58..3a8751a8b92ddefd91d9948cc8cbfa7cc6dd3301 100644 (file)
@@ -244,7 +244,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);
 }
 
@@ -278,6 +278,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 3813c1ede450ee321e76c26f8d7677094a75ada9..c23e6f5e2514174a83b2a6a8119f53f8099ec25a 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_declare_wedged(struct xe_uc *uc);