]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/xe/gsc: Fix GSC proxy cleanup on early initialization failure
authorZhanjun Dong <zhanjun.dong@intel.com>
Fri, 20 Feb 2026 22:53:08 +0000 (17:53 -0500)
committerSasha Levin <sashal@kernel.org>
Thu, 12 Mar 2026 11:09:54 +0000 (07:09 -0400)
[ Upstream commit b3368ecca9538b88ddf982ea99064860fd5add97 ]

xe_gsc_proxy_remove undoes what is done in both xe_gsc_proxy_init and
xe_gsc_proxy_start; however, if we fail between those 2 calls, it is
possible that the HW forcewake access hasn't been initialized yet and so
we hit errors when the cleanup code tries to write GSC register. To
avoid that, split the cleanup in 2 functions so that the HW cleanup is
only called if the HW setup was completed successfully.

Since the HW cleanup (interrupt disabling) is now removed from
xe_gsc_proxy_remove, the cleanup on error paths in xe_gsc_proxy_start
must be updated to disable interrupts before returning.

Fixes: ff6cd29b690b ("drm/xe: Cleanup unwind of gt initialization")
Signed-off-by: Zhanjun Dong <zhanjun.dong@intel.com>
Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Link: https://patch.msgid.link/20260220225308.101469-1-zhanjun.dong@intel.com
(cherry picked from commit 2b37c401b265c07b46408b5cb36a4b757c9b5060)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/xe/xe_gsc_proxy.c
drivers/gpu/drm/xe/xe_gsc_types.h

index 464282a89eef39619d0360188aed91c4163bec28..a6f6f0ea56526fa1eb9d6fb785e5072c08b72685 100644 (file)
@@ -435,16 +435,12 @@ static int proxy_channel_alloc(struct xe_gsc *gsc)
        return 0;
 }
 
-static void xe_gsc_proxy_remove(void *arg)
+static void xe_gsc_proxy_stop(struct xe_gsc *gsc)
 {
-       struct xe_gsc *gsc = arg;
        struct xe_gt *gt = gsc_to_gt(gsc);
        struct xe_device *xe = gt_to_xe(gt);
        unsigned int fw_ref = 0;
 
-       if (!gsc->proxy.component_added)
-               return;
-
        /* disable HECI2 IRQs */
        xe_pm_runtime_get(xe);
        fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC);
@@ -458,6 +454,30 @@ static void xe_gsc_proxy_remove(void *arg)
        xe_pm_runtime_put(xe);
 
        xe_gsc_wait_for_worker_completion(gsc);
+       gsc->proxy.started = false;
+}
+
+static void xe_gsc_proxy_remove(void *arg)
+{
+       struct xe_gsc *gsc = arg;
+       struct xe_gt *gt = gsc_to_gt(gsc);
+       struct xe_device *xe = gt_to_xe(gt);
+
+       if (!gsc->proxy.component_added)
+               return;
+
+       /*
+        * GSC proxy start is an async process that can be ongoing during
+        * Xe module load/unload. Using devm managed action to register
+        * xe_gsc_proxy_stop could cause issues if Xe module unload has
+        * already started when the action is registered, potentially leading
+        * to the cleanup being called at the wrong time. Therefore, instead
+        * of registering a separate devm action to undo what is done in
+        * proxy start, we call it from here, but only if the start has
+        * completed successfully (tracked with the 'started' flag).
+        */
+       if (gsc->proxy.started)
+               xe_gsc_proxy_stop(gsc);
 
        component_del(xe->drm.dev, &xe_gsc_proxy_component_ops);
        gsc->proxy.component_added = false;
@@ -513,6 +533,7 @@ int xe_gsc_proxy_init(struct xe_gsc *gsc)
  */
 int xe_gsc_proxy_start(struct xe_gsc *gsc)
 {
+       struct xe_gt *gt = gsc_to_gt(gsc);
        int err;
 
        /* enable the proxy interrupt in the GSC shim layer */
@@ -524,12 +545,18 @@ int xe_gsc_proxy_start(struct xe_gsc *gsc)
         */
        err = xe_gsc_proxy_request_handler(gsc);
        if (err)
-               return err;
+               goto err_irq_disable;
 
        if (!xe_gsc_proxy_init_done(gsc)) {
-               xe_gt_err(gsc_to_gt(gsc), "GSC FW reports proxy init not completed\n");
-               return -EIO;
+               xe_gt_err(gt, "GSC FW reports proxy init not completed\n");
+               err = -EIO;
+               goto err_irq_disable;
        }
 
+       gsc->proxy.started = true;
        return 0;
+
+err_irq_disable:
+       gsc_proxy_irq_toggle(gsc, false);
+       return err;
 }
index 97c056656df05b573e8ab94180e70cbb474c079f..5aaa2a75861fd2ad12f5dcd96b0bbe882acbcf56 100644 (file)
@@ -58,6 +58,8 @@ struct xe_gsc {
                struct mutex mutex;
                /** @proxy.component_added: whether the component has been added */
                bool component_added;
+               /** @proxy.started: whether the proxy has been started */
+               bool started;
                /** @proxy.bo: object to store message to and from the GSC */
                struct xe_bo *bo;
                /** @proxy.to_gsc: map of the memory used to send messages to the GSC */