From be4518128a58f61862bec66621e5d3da254a97ce Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Thu, 18 Dec 2025 14:38:57 -0800 Subject: [PATCH] drm/xe/pf: Add functions to set preempt timeouts for each group The KLV to set the preemption timeout for each groups works the exact same way as the one for the exec quantums, so we add similar functions. Signed-off-by: Daniele Ceraolo Spurio Cc: Michal Wajdeczko Reviewed-by: Michal Wajdeczko Link: https://patch.msgid.link/20251218223846.1146344-25-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/abi/guc_klvs_abi.h | 13 +++ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 95 +++++++++++++++++++++- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h | 5 ++ drivers/gpu/drm/xe/xe_guc_klv_helpers.c | 2 + 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h index dc753c317ae0..e33bd622ab44 100644 --- a/drivers/gpu/drm/xe/abi/guc_klvs_abi.h +++ b/drivers/gpu/drm/xe/abi/guc_klvs_abi.h @@ -405,6 +405,16 @@ enum { * the GuC always sets the EQ for all groups (even the non-enabled ones), * so if we provide fewer values than the max the GuC will use 0 for the * remaining groups. This KLV is available starting from GuC 70.53.0. + * + * _`GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT' : 0x8A0F + * This config sets the VFs-preemption-timeout for each scheduling group in + * microseconds. The driver must provide an array of values, with each of + * them matching the respective group index (first value goes to group 0, + * second to group 1, etc). The setting of group values follows the same + * behavior and rules as setting via GUC_KLV_VF_CFG_PREEMPT_TIMEOUT. Note + * that the GuC always sets the EQ for all groups (even the non-enabled + * ones), so if we provide fewer values than the max the GuC will use 0 for + * the remaining groups. This KLV is available starting from GuC 70.53.0. */ #define GUC_KLV_VF_CFG_GGTT_START_KEY 0x0001 @@ -470,6 +480,9 @@ enum { #define GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_MIN_LEN 1u #define GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_MAX_LEN GUC_MAX_SCHED_GROUPS +#define GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY 0x8a0f +#define GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_MIN_LEN 1u +#define GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_MAX_LEN GUC_MAX_SCHED_GROUPS /* * Workaround keys: */ diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index c663f349b437..5a870914b102 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -295,13 +295,18 @@ static u32 encode_config_sched(struct xe_gt *gt, u32 *cfg, u32 n, if (xe_sriov_gt_pf_policy_has_multi_group_modes(gt)) { BUILD_BUG_ON(ARRAY_SIZE(config->exec_quantum) > GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_MAX_LEN); + BUILD_BUG_ON(ARRAY_SIZE(config->preempt_timeout) > + GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_MAX_LEN); cfg[n++] = PREP_GUC_KLV_CONST(GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_KEY, ARRAY_SIZE(config->exec_quantum)); for (i = 0; i < ARRAY_SIZE(config->exec_quantum); i++) cfg[n++] = config->exec_quantum[i]; - /* TODO: add group preempt timeout setting */ + cfg[n++] = PREP_GUC_KLV_CONST(GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY, + ARRAY_SIZE(config->preempt_timeout)); + for (i = 0; i < ARRAY_SIZE(config->preempt_timeout); i++) + cfg[n++] = config->preempt_timeout[i]; } else { cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_EXEC_QUANTUM); cfg[n++] = config->exec_quantum[0]; @@ -2265,6 +2270,89 @@ int xe_gt_sriov_pf_config_bulk_set_preempt_timeout_locked(struct xe_gt *gt, u32 preempt_timeout_unit, n, err); } +static int pf_provision_groups_preempt_timeouts(struct xe_gt *gt, unsigned int vfid, + const u32 *preempt_timeouts, u32 count) +{ + struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid); + int err; + int i; + + err = pf_push_vf_grp_cfg_u32(gt, vfid, GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY, + preempt_timeouts, count); + if (unlikely(err)) + return err; + + /* + * GuC silently clamps values exceeding the max and zeroes out the + * quantum for groups not in the klv payload + */ + for (i = 0; i < ARRAY_SIZE(config->preempt_timeout); i++) { + if (i < count) + config->preempt_timeout[i] = + min_t(u32, preempt_timeouts[i], + GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_MAX_VALUE); + else + config->preempt_timeout[i] = 0; + } + + return 0; +} + +static void pf_get_groups_preempt_timeouts(struct xe_gt *gt, unsigned int vfid, + u32 *preempt_timeouts, u32 max_count) +{ + struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid); + u32 count = min_t(u32, max_count, ARRAY_SIZE(config->preempt_timeout)); + + memcpy(preempt_timeouts, config->preempt_timeout, sizeof(u32) * count); +} + +/** + * xe_gt_sriov_pf_config_set_groups_preempt_timeouts() - Configure PF/VF PTs for sched groups. + * @gt: the &xe_gt + * @vfid: the PF or VF identifier + * @preempt_timeouts: array of requested PTs in microseconds (0 is infinity) + * @count: number of entries in the array + * + * This function can only be called on PF. + * It will log the provisioned value or an error in case of the failure. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_gt_sriov_pf_config_set_groups_preempt_timeouts(struct xe_gt *gt, unsigned int vfid, + u32 *preempt_timeouts, u32 count) +{ + int err; + + guard(mutex)(xe_gt_sriov_pf_master_mutex(gt)); + + err = pf_provision_groups_preempt_timeouts(gt, vfid, preempt_timeouts, count); + + return pf_groups_cfg_set_u32_done(gt, vfid, preempt_timeouts, count, + pf_get_groups_preempt_timeouts, + "preempt_timeout", + preempt_timeout_unit, err); +} + +/** + * xe_gt_sriov_pf_config_get_groups_preempt_timeouts() - Get PF/VF sched groups PTs + * @gt: the &xe_gt + * @vfid: the PF or VF identifier + * @preempt_timeouts: array in which to store the preemption timeouts values + * @count: maximum number of entries to store + * + * This function can only be called on PF. + */ +void xe_gt_sriov_pf_config_get_groups_preempt_timeouts(struct xe_gt *gt, unsigned int vfid, + u32 *preempt_timeouts, u32 count) +{ + guard(mutex)(xe_gt_sriov_pf_master_mutex(gt)); + + xe_gt_assert(gt, count <= GUC_MAX_SCHED_GROUPS); + + pf_get_groups_preempt_timeouts(gt, vfid, preempt_timeouts, count); +} + static const char *sched_priority_unit(u32 priority) { return priority == GUC_SCHED_PRIORITY_LOW ? "(low)" : @@ -2712,6 +2800,11 @@ static int pf_restore_vf_config_klv(struct xe_gt *gt, unsigned int vfid, return -EBADMSG; return pf_provision_groups_exec_quantums(gt, vfid, value, len); + case GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY: + if (len > GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_MAX_LEN) + return -EBADMSG; + return pf_provision_groups_preempt_timeouts(gt, vfid, value, len); + case GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_KEY: if (len != GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_LEN) return -EBADMSG; diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h index aaed1f490da8..3c6c8b6655af 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h @@ -60,6 +60,11 @@ int xe_gt_sriov_pf_config_set_preempt_timeout_locked(struct xe_gt *gt, unsigned u32 preempt_timeout); int xe_gt_sriov_pf_config_bulk_set_preempt_timeout_locked(struct xe_gt *gt, u32 preempt_timeout); +void xe_gt_sriov_pf_config_get_groups_preempt_timeouts(struct xe_gt *gt, unsigned int vfid, + u32 *preempt_timeout, u32 max_count); +int xe_gt_sriov_pf_config_set_groups_preempt_timeouts(struct xe_gt *gt, unsigned int vfid, + u32 *preempt_timeout, u32 count); + u32 xe_gt_sriov_pf_config_get_sched_priority(struct xe_gt *gt, unsigned int vfid); int xe_gt_sriov_pf_config_set_sched_priority(struct xe_gt *gt, unsigned int vfid, u32 priority); diff --git a/drivers/gpu/drm/xe/xe_guc_klv_helpers.c b/drivers/gpu/drm/xe/xe_guc_klv_helpers.c index b696a21f87e8..97600edda837 100644 --- a/drivers/gpu/drm/xe/xe_guc_klv_helpers.c +++ b/drivers/gpu/drm/xe/xe_guc_klv_helpers.c @@ -58,6 +58,8 @@ const char *xe_guc_klv_key_to_string(u16 key) return "sched_priority"; case GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_KEY: return "sched_groups_exec_quantum"; + case GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY: + return "sched_groups_preempt_timeout"; /* VF CFG threshold keys */ #define define_threshold_key_to_string_case(TAG, NAME, ...) \ -- 2.47.3