]> 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)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Thu, 18 Sep 2025 00:23:47 +0000 (20:23 -0400)
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]

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 81eb046aeebfef4fe684e2481bd857b5b23010a3..b9f67d7a00d87938867eb710d42fc6bd92d2327c 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 0366a9da59775181691908916dc32e0d399a3c33..d7719d0e36ca78b3dfb6287071cc5443a13c54f5 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`_                             |
  *  |   |       |                                                              |
@@ -152,6 +153,30 @@ enum  {
 #define GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH_KEY 0x4003
 #define GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH_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 c8eda36546d343c531502bfed7da9e801e5a7123..17634195cdc26a499727d8d2cc5fc2b3858f5c83 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 b1d1d6da37581ea1468bfa953455b6b27b9beef0..270fc3792493668977130ce82142f51b29643c57 100644 (file)
@@ -880,9 +880,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)
@@ -1579,7 +1577,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 93fc7b290b655f95139346dfc3e269fda3b7ed76..0104afbc941c84e11c17e6f44b5d131ba792216f 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);