]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/xe/guc: Set RCS/CCS yield policy
authorDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Fri, 5 Sep 2025 23:56:33 +0000 (16:56 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Sep 2025 09:16:52 +0000 (11:16 +0200)
[ Upstream commit 26caeae9fb482ec443753b4e3307e5122b60b850 ]

All recent platforms (including all the ones officially supported by the
Xe driver) do not allow concurrent execution of RCS and CCS workloads
from different address spaces, with the HW blocking the context switch
when it detects such a scenario.
The DUAL_QUEUE flag helps with this, by causing the GuC to not submit a
context it knows will not be able to execute. This, however, causes a new
problem: if RCS and CCS queues have pending workloads from different
address spaces, the GuC needs to choose from which of the 2 queues to
pick the next workload to execute. By default, the GuC prioritizes RCS
submissions over CCS ones, which can lead to CCS workloads being
significantly (or completely) starved of execution time.
The driver can tune this by setting a dedicated scheduling policy KLV;
this KLV allows the driver to specify a quantum (in ms) and a ratio
(percentage value between 0 and 100), and the GuC will prioritize the CCS
for that percentage of each quantum.
Given that we want to guarantee enough RCS throughput to avoid missing
frames, we set the yield policy to 20% of each 80ms interval.

v2: updated quantum and ratio, improved comment, use xe_guc_submit_disable
in gt_sanitize

Fixes: d9a1ae0d17bd ("drm/xe/guc: Enable WA_DUAL_QUEUE for newer platforms")
Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: John Harrison <John.C.Harrison@Intel.com>
Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Reviewed-by: John Harrison <John.C.Harrison@Intel.com>
Tested-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Link: https://lore.kernel.org/r/20250905235632.3333247-2-daniele.ceraolospurio@intel.com
(cherry picked from commit 88434448438e4302e272b2a2b810b42e05ea024b)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
[Rodrigo added #include "xe_guc_submit.h" while backporting]
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/xe/abi/guc_actions_abi.h
drivers/gpu/drm/xe/abi/guc_klvs_abi.h
drivers/gpu/drm/xe/xe_gt.c
drivers/gpu/drm/xe/xe_guc.c
drivers/gpu/drm/xe/xe_guc_submit.c
drivers/gpu/drm/xe/xe_guc_submit.h

index b55d4cfb483a171352123d2fce88491038045e8d..4d9896e14649c0af041a62d53ce3e088fba54377 100644 (file)
@@ -117,6 +117,7 @@ enum xe_guc_action {
        XE_GUC_ACTION_ENTER_S_STATE = 0x501,
        XE_GUC_ACTION_EXIT_S_STATE = 0x502,
        XE_GUC_ACTION_GLOBAL_SCHED_POLICY_CHANGE = 0x506,
+       XE_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV = 0x509,
        XE_GUC_ACTION_SCHED_CONTEXT = 0x1000,
        XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET = 0x1001,
        XE_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002,
index 5b2502bec2dcc708e2851e041dad8d082cb7710a..89034bc97ec5a42efe1f155307a6f0b1d528b332 100644 (file)
@@ -17,6 +17,7 @@
  *  | 0 | 31:16 | **KEY** - KLV key identifier                                 |
  *  |   |       |   - `GuC Self Config KLVs`_                                  |
  *  |   |       |   - `GuC Opt In Feature KLVs`_                               |
+ *  |   |       |   - `GuC Scheduling Policies KLVs`_                          |
  *  |   |       |   - `GuC VGT Policy KLVs`_                                   |
  *  |   |       |   - `GuC VF Configuration KLVs`_                             |
  *  |   |       |                                                              |
@@ -139,6 +140,30 @@ enum  {
 #define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_KEY 0x4001
 #define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_LEN 0u
 
+/**
+ * DOC: GuC Scheduling Policies KLVs
+ *
+ * `GuC KLV`_ keys available for use with UPDATE_SCHEDULING_POLICIES_KLV.
+ *
+ * _`GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD` : 0x1001
+ *      Some platforms do not allow concurrent execution of RCS and CCS
+ *      workloads from different address spaces. By default, the GuC prioritizes
+ *      RCS submissions over CCS ones, which can lead to CCS workloads being
+ *      significantly (or completely) starved of execution time. This KLV allows
+ *      the driver to specify a quantum (in ms) and a ratio (percentage value
+ *      between 0 and 100), and the GuC will prioritize the CCS for that
+ *      percentage of each quantum. For example, specifying 100ms and 30% will
+ *      make the GuC prioritize the CCS for 30ms of every 100ms.
+ *      Note that this does not necessarly mean that RCS and CCS engines will
+ *      only be active for their percentage of the quantum, as the restriction
+ *      only kicks in if both classes are fully busy with non-compatible address
+ *      spaces; i.e., if one engine is idle or running the same address space,
+ *      a pending job on the other engine will still be submitted to the HW no
+ *      matter what the ratio is
+ */
+#define GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD_KEY   0x1001
+#define GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD_LEN   2u
+
 /**
  * DOC: GuC VGT Policy KLVs
  *
index e3517ce2e18c14a77ed7aa64acedba0459d16694..eaf7569a7c1d1ec286f70dcb29875d335001a143 100644 (file)
@@ -41,6 +41,7 @@
 #include "xe_gt_topology.h"
 #include "xe_guc_exec_queue_types.h"
 #include "xe_guc_pc.h"
+#include "xe_guc_submit.h"
 #include "xe_hw_fence.h"
 #include "xe_hw_engine_class_sysfs.h"
 #include "xe_irq.h"
@@ -97,7 +98,7 @@ void xe_gt_sanitize(struct xe_gt *gt)
         * FIXME: if xe_uc_sanitize is called here, on TGL driver will not
         * reload
         */
-       gt->uc.guc.submission_state.enabled = false;
+       xe_guc_submit_disable(&gt->uc.guc);
 }
 
 static void xe_gt_enable_host_l2_vram(struct xe_gt *gt)
index 2efc0298e1a4c3638227172319f346a080ec14c5..b9d21fdaad48ba68c291038cb3ffff53b18146fa 100644 (file)
@@ -825,9 +825,7 @@ int xe_guc_post_load_init(struct xe_guc *guc)
                        return ret;
        }
 
-       guc->submission_state.enabled = true;
-
-       return 0;
+       return xe_guc_submit_enable(guc);
 }
 
 int xe_guc_reset(struct xe_guc *guc)
@@ -1521,7 +1519,7 @@ void xe_guc_sanitize(struct xe_guc *guc)
 {
        xe_uc_fw_sanitize(&guc->fw);
        xe_guc_ct_disable(&guc->ct);
-       guc->submission_state.enabled = false;
+       xe_guc_submit_disable(guc);
 }
 
 int xe_guc_reset_prepare(struct xe_guc *guc)
index e670dcb0f093273e85fab9a46bde81ae627eea8e..18ddbb7b98a15b1f15fd8af14537f47f96d110f3 100644 (file)
@@ -32,6 +32,7 @@
 #include "xe_guc_ct.h"
 #include "xe_guc_exec_queue_types.h"
 #include "xe_guc_id_mgr.h"
+#include "xe_guc_klv_helpers.h"
 #include "xe_guc_submit_types.h"
 #include "xe_hw_engine.h"
 #include "xe_hw_fence.h"
@@ -316,6 +317,71 @@ int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids)
        return drmm_add_action_or_reset(&xe->drm, guc_submit_fini, guc);
 }
 
+/*
+ * Given that we want to guarantee enough RCS throughput to avoid missing
+ * frames, we set the yield policy to 20% of each 80ms interval.
+ */
+#define RC_YIELD_DURATION      80      /* in ms */
+#define RC_YIELD_RATIO         20      /* in percent */
+static u32 *emit_render_compute_yield_klv(u32 *emit)
+{
+       *emit++ = PREP_GUC_KLV_TAG(SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD);
+       *emit++ = RC_YIELD_DURATION;
+       *emit++ = RC_YIELD_RATIO;
+
+       return emit;
+}
+
+#define SCHEDULING_POLICY_MAX_DWORDS 16
+static int guc_init_global_schedule_policy(struct xe_guc *guc)
+{
+       u32 data[SCHEDULING_POLICY_MAX_DWORDS];
+       u32 *emit = data;
+       u32 count = 0;
+       int ret;
+
+       if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 1, 0))
+               return 0;
+
+       *emit++ = XE_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV;
+
+       if (CCS_MASK(guc_to_gt(guc)))
+               emit = emit_render_compute_yield_klv(emit);
+
+       count = emit - data;
+       if (count > 1) {
+               xe_assert(guc_to_xe(guc), count <= SCHEDULING_POLICY_MAX_DWORDS);
+
+               ret = xe_guc_ct_send_block(&guc->ct, data, count);
+               if (ret < 0) {
+                       xe_gt_err(guc_to_gt(guc),
+                                 "failed to enable GuC sheduling policies: %pe\n",
+                                 ERR_PTR(ret));
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+int xe_guc_submit_enable(struct xe_guc *guc)
+{
+       int ret;
+
+       ret = guc_init_global_schedule_policy(guc);
+       if (ret)
+               return ret;
+
+       guc->submission_state.enabled = true;
+
+       return 0;
+}
+
+void xe_guc_submit_disable(struct xe_guc *guc)
+{
+       guc->submission_state.enabled = false;
+}
+
 static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q, u32 xa_count)
 {
        int i;
index 9b71a986c6ca69ebe1cf81df6ffbbfb2e2c82e6e..0d126b807c1041c517adc26159e3b28f6edc3185 100644 (file)
@@ -13,6 +13,8 @@ struct xe_exec_queue;
 struct xe_guc;
 
 int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids);
+int xe_guc_submit_enable(struct xe_guc *guc);
+void xe_guc_submit_disable(struct xe_guc *guc);
 
 int xe_guc_submit_reset_prepare(struct xe_guc *guc);
 void xe_guc_submit_reset_wait(struct xe_guc *guc);