]> www.infradead.org Git - users/jedix/linux-maple.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)
committerDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Thu, 11 Sep 2025 16:45:35 +0000 (09:45 -0700)
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
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 d8cf68a0516d5bf0c4a94fb1b4f06b89193fab2f..1baa969aaa7cad75bcc882ca33415a668ca93cb8 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 0e78351c6ef5afb840f54125419507ddd3b5df7b..265a135e7061ebac70d02a4c6f97b6a61f6334fa 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 34505a6d93ed5a0ab652dc418b5c445f5f876deb..3e0ad7e5b5dfbae711ad153a7b588d155b52abf7 100644 (file)
@@ -98,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 e56c9c5c8845e1912882eac38dcff3e7b44e6a7d..4eb06ffc09bc2b45d04f56025f4fa6d06544dcc4 100644 (file)
@@ -879,9 +879,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)
@@ -1593,7 +1591,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 5ab242be50dd60195f4e8c0d5af5b40708202e5f..a465594b61dca4062a7657798a8dc2e1a19d1503 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 9e6f19b03e6542585f981e5bdb296cfa4327db21..78c3f07e31a0a0b0dc74c3df853617ad5c19565d 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);