drm/xe/gsc: Implement WA 14015076503
authorDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Fri, 17 Nov 2023 22:51:48 +0000 (14:51 -0800)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Thu, 21 Dec 2023 16:45:06 +0000 (11:45 -0500)
When the GSC FW is loaded, we need to inform it when a GSCCS reset is
coming and then wait 200ms for it to get ready to process the reset.

v2: move WA code to GSC file, use variable in Makefile (John)

Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: John Harrison <john.c.harrison@intel.com>
Reviewed-by: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/xe/Makefile
drivers/gpu/drm/xe/regs/xe_gsc_regs.h
drivers/gpu/drm/xe/xe_gsc.c
drivers/gpu/drm/xe/xe_gsc.h
drivers/gpu/drm/xe/xe_gt.c
drivers/gpu/drm/xe/xe_wa_oob.rules

index 184e2724ce7ba9ba0ac3f5695f978517d778a453..5806ebb0256ae995db6cc3caca78019b813a2afd 100644 (file)
@@ -37,7 +37,16 @@ quiet_cmd_wa_oob = GEN     $(notdir $(generated_oob))
 $(generated_oob) &: $(obj)/xe_gen_wa_oob $(srctree)/$(src)/xe_wa_oob.rules
        $(call cmd,wa_oob)
 
-$(obj)/xe_guc.o $(obj)/xe_migrate.o $(obj)/xe_ring_ops.o $(obj)/xe_vm.o $(obj)/xe_wa.o $(obj)/xe_ttm_stolen_mgr.o: $(generated_oob)
+uses_generated_oob := \
+       $(obj)/xe_gsc.o \
+       $(obj)/xe_guc.o \
+       $(obj)/xe_migrate.o \
+       $(obj)/xe_ring_ops.o \
+       $(obj)/xe_vm.o \
+       $(obj)/xe_wa.o \
+       $(obj)/xe_ttm_stolen_mgr.o
+
+$(uses_generated_oob): $(generated_oob)
 
 # Please keep these build lists sorted!
 
index 22d2ad9cb64dcc3adfd9090edd388355f5cba27b..9a84b55d66eee1c9cba769df07bb050d56a4cd1d 100644 (file)
 #define MTL_GSC_HECI1_BASE     0x00116000
 #define MTL_GSC_HECI2_BASE     0x00117000
 
+#define HECI_H_CSR(base)       XE_REG((base) + 0x4)
+#define   HECI_H_CSR_IE                REG_BIT(0)
+#define   HECI_H_CSR_IS                REG_BIT(1)
+#define   HECI_H_CSR_IG                REG_BIT(2)
+#define   HECI_H_CSR_RDY       REG_BIT(3)
+#define   HECI_H_CSR_RST       REG_BIT(4)
+
 /*
  * The FWSTS register values are FW defined and can be different between
  * HECI1 and HECI2
@@ -26,4 +33,7 @@
 #define   HECI1_FWSTS1_PROXY_STATE_NORMAL              5
 #define   HECI1_FWSTS1_INIT_COMPLETE                   REG_BIT(9)
 
+#define HECI_H_GS1(base)       XE_REG((base) + 0xc4c)
+#define   HECI_H_GS1_ER_PREP   REG_BIT(0)
+
 #endif
index e014b829bc8af8edb42160409259051e35d8cac0..5731c026a77a1701cfc523c37db7b1acb7f4c93e 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <drm/drm_managed.h>
 
+#include "generated/xe_wa_oob.h"
 #include "xe_bb.h"
 #include "xe_bo.h"
 #include "xe_device.h"
@@ -17,6 +18,7 @@
 #include "xe_mmio.h"
 #include "xe_sched_job.h"
 #include "xe_uc_fw.h"
+#include "xe_wa.h"
 #include "instructions/xe_gsc_commands.h"
 #include "regs/xe_gsc_regs.h"
 
@@ -300,3 +302,30 @@ void xe_gsc_wait_for_worker_completion(struct xe_gsc *gsc)
        if (xe_uc_fw_is_loadable(&gsc->fw) && gsc->wq)
                flush_work(&gsc->work);
 }
+
+/*
+ * 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
+ * triggering an interrupt to GSC; from the interrupt it will take up to 200ms
+ * for the FW to get prepare for the reset, so we need to wait for that amount
+ * of time.
+ * After the reset is complete we need to then clear the GS1 register.
+ */
+void xe_gsc_wa_14015076503(struct xe_gt *gt, bool prep)
+{
+       u32 gs1_set = prep ? HECI_H_GS1_ER_PREP : 0;
+       u32 gs1_clr = prep ? 0 : HECI_H_GS1_ER_PREP;
+
+       /* WA only applies if the GSC is loaded */
+       if (!XE_WA(gt, 14015076503) || !gsc_fw_is_loaded(gt))
+               return;
+
+       xe_mmio_rmw32(gt, HECI_H_GS1(MTL_GSC_HECI2_BASE), gs1_clr, gs1_set);
+
+       if (prep) {
+               /* make sure the reset bit is clear when writing the CSR reg */
+               xe_mmio_rmw32(gt, HECI_H_CSR(MTL_GSC_HECI2_BASE),
+                             HECI_H_CSR_RST, HECI_H_CSR_IG);
+               msleep(200);
+       }
+}
index f870eddc77d4ebf5da20f2f124a7ded6f8a7f587..bc1ef7f31ea2c2e69054e22d69d4dff23db47579 100644 (file)
@@ -8,9 +8,13 @@
 
 #include "xe_gsc_types.h"
 
+struct xe_gt;
+
 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_load_start(struct xe_gsc *gsc);
 
+void xe_gsc_wa_14015076503(struct xe_gt *gt, bool prep);
+
 #endif
index 0dddb751c6a48263ed5760890cdec22b03a0f62d..00193b02a7e54f59f99c36a5736efa3efe6f932b 100644 (file)
@@ -21,6 +21,7 @@
 #include "xe_execlist.h"
 #include "xe_force_wake.h"
 #include "xe_ggtt.h"
+#include "xe_gsc.h"
 #include "xe_gt_clock.h"
 #include "xe_gt_idle_sysfs.h"
 #include "xe_gt_mcr.h"
@@ -512,12 +513,16 @@ static int do_gt_reset(struct xe_gt *gt)
 {
        int err;
 
+       xe_gsc_wa_14015076503(gt, true);
+
        xe_mmio_write32(gt, GDRST, GRDOM_FULL);
        err = xe_mmio_wait32(gt, GDRST, GRDOM_FULL, 0, 5000, NULL, false);
        if (err)
                xe_gt_err(gt, "failed to clear GRDOM_FULL (%pe)\n",
                          ERR_PTR(err));
 
+       xe_gsc_wa_14015076503(gt, false);
+
        return err;
 }
 
index 752842d734be02797c62ff9d2d740e675feb070c..c7b7d40b5d5757fb32a5b90ae1caa04946d08974 100644 (file)
@@ -20,3 +20,4 @@
 16017236439    PLATFORM(PVC)
 22010954014    PLATFORM(DG2)
 14019821291    MEDIA_VERSION_RANGE(1300, 2000)
+14015076503    MEDIA_VERSION(1300)