From: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
To: Michal Wajdeczko <michal.wajdeczko@intel.com>,
<intel-xe@lists.freedesktop.org>
Subject: Re: [PATCH v3 03/12] drm/xe/sriov: Initialize scheduler groups
Date: Thu, 11 Dec 2025 14:55:02 -0800 [thread overview]
Message-ID: <5fa62765-a018-4712-b966-c8eca9b3cb2b@intel.com> (raw)
In-Reply-To: <143fc553-229e-4bf8-8494-abb06cf7ade2@intel.com>
On 12/11/2025 10:52 AM, Michal Wajdeczko wrote:
>
> On 12/11/2025 2:57 AM, Daniele Ceraolo Spurio wrote:
>> Scheduler groups (a.k.a. Engine Groups Scheduling, or EGS) is a GuC
>> feature that allows the driver to define groups of engines that are
>> independently scheduled across VFs, which allows different VFs to be
>> active on the HW at the same time on different groups. The feature is
>> available for BMG and newer HW starting on GuC 70.53.0, but some
>> required fixes have been added to GuC 70.55.1.
>>
>> This is intended for specific scenarios where the admin knows that the
>> VFs are not going to fully utilize the HW and therefore assigning all of
>> it to a single VF would lead to part of it being permanently idle.
>> We do not allow the admin to decide how to divide the engines across
>> groups, but we instead support specific configurations that are designed
>> for specific use-cases. During PF initialization we detect which
>> configurations are possible on a given GT and create the relevant
>> groups. Since the GuC expect a mask for each class for each group, that
>> is what we save when we init the configs.
>>
>> Right now we only have one use-case on the media GT. If the VFs are
>> running a frame render + encoding at a not-too-high resolution (e.g.
>> 1080@30fps) the render can produce frames faster than the video engine
>> can encode them, which means that the maximum number of parallel VFs is
>> limited by the VCS bandwidth. Since our products can have multiple VCS
>> engines, allowing multiple VFs to be active on the different VCS engines
>> at the same time allows us to run more parallel VFs on the same HW.
>> Given that engines in the same media slice share some resources (e.g.
>> SFC), we assign each media slice to a different scheduling group. We
>> refer to this configuration as "media_slices", given that each slice
>> gets its own group. Since upcoming products have a different number of
>> video engines per-slice, for now we limit the media_slices mode to BMG,
>> but we expect to add support for newer HW soon.
>>
>> Note that while the GuC interface supports a maximum of 8 groups, the
>> actual number of groups that can be enabled can be lower than that and
>> can be different on different devices. For now, all devices support up
>> to 2 groups.
>>
>> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
>> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
>> ---
>> v2: Use asserts for coding errors, code cleanups, better docs (Michal),
>> limit groups to 2, limit to BMG and newer, bump required GuC to
>> 70.55.1.
>> v3: Use a struct sched_groups array instead of an array of u32 masks,
>> move the max_group check to the next patch, rename NONE to
>> DISABLED (Michal), limit the media_slices mode to BMG.
>> ---
>> drivers/gpu/drm/xe/abi/guc_scheduler_abi.h | 9 ++
>> drivers/gpu/drm/xe/xe_gt.h | 3 +
>> drivers/gpu/drm/xe/xe_gt_sriov_pf.c | 3 +
>> drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c | 142 ++++++++++++++++++
>> drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.h | 2 +
>> .../gpu/drm/xe/xe_gt_sriov_pf_policy_types.h | 33 ++++
>> 6 files changed, 192 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/xe/abi/guc_scheduler_abi.h b/drivers/gpu/drm/xe/abi/guc_scheduler_abi.h
>> index db9c171f8b64..513b22a87428 100644
>> --- a/drivers/gpu/drm/xe/abi/guc_scheduler_abi.h
>> +++ b/drivers/gpu/drm/xe/abi/guc_scheduler_abi.h
>> @@ -6,6 +6,8 @@
>> #ifndef _ABI_GUC_SCHEDULER_ABI_H
>> #define _ABI_GUC_SCHEDULER_ABI_H
>>
>> +#include <linux/types.h>
>> +
>> /**
>> * Generic defines required for registration with and submissions to the GuC
>> * scheduler. Includes engine class/instance defines and context attributes
>> @@ -45,4 +47,11 @@
>> #define GUC_CONTEXT_DISABLE 0
>> #define GUC_CONTEXT_ENABLE 1
>>
>> +/* scheduler groups */
>> +#define GUC_MAX_SCHED_GROUPS 8
>> +
>> +struct guc_sched_group {
>> + u32 engines[GUC_MAX_ENGINE_CLASSES];
>> +} __packed;
>> +
>> #endif
>> diff --git a/drivers/gpu/drm/xe/xe_gt.h b/drivers/gpu/drm/xe/xe_gt.h
>> index a2ba80c954a6..de7e47763411 100644
>> --- a/drivers/gpu/drm/xe/xe_gt.h
>> +++ b/drivers/gpu/drm/xe/xe_gt.h
>> @@ -29,6 +29,9 @@
>> #define CCS_INSTANCES(gt) XE_ENGINE_INSTANCES_FROM_MASK(gt, CCS)
>> #define GSCCS_INSTANCES(gt) XE_ENGINE_INSTANCES_FROM_MASK(gt, GSCCS)
>>
>> +/* Our devices have up to 4 media slices */
>> +#define MAX_MEDIA_SLICES 4
>> +
>> #define GT_VER(gt) ({ \
>> typeof(gt) gt_ = (gt); \
>> struct xe_device *xe = gt_to_xe(gt_); \
>> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
>> index 0714c758b9c1..0d97a823e702 100644
>> --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
>> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c
>> @@ -14,6 +14,7 @@
>> #include "xe_gt_sriov_pf_control.h"
>> #include "xe_gt_sriov_pf_helpers.h"
>> #include "xe_gt_sriov_pf_migration.h"
>> +#include "xe_gt_sriov_pf_policy.h"
>> #include "xe_gt_sriov_pf_service.h"
>> #include "xe_gt_sriov_printk.h"
>> #include "xe_guc_submit.h"
>> @@ -123,6 +124,8 @@ int xe_gt_sriov_pf_init(struct xe_gt *gt)
>> if (err)
>> return err;
>>
>> + xe_gt_sriov_pf_policy_init(gt);
>> +
>> err = xe_gt_sriov_pf_migration_init(gt);
>> if (err)
>> return err;
>> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c
>> index 4445f660e6d1..003860661687 100644
>> --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c
>> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c
>> @@ -3,6 +3,8 @@
>> * Copyright © 2023-2024 Intel Corporation
>> */
>>
>> +#include <drm/drm_managed.h>
>> +
>> #include "abi/guc_actions_sriov_abi.h"
>>
>> #include "xe_bo.h"
>> @@ -10,6 +12,7 @@
>> #include "xe_gt_sriov_pf_helpers.h"
>> #include "xe_gt_sriov_pf_policy.h"
>> #include "xe_gt_sriov_printk.h"
>> +#include "xe_guc.h"
>> #include "xe_guc_buf.h"
>> #include "xe_guc_ct.h"
>> #include "xe_guc_klv_helpers.h"
>> @@ -351,6 +354,133 @@ u32 xe_gt_sriov_pf_policy_get_sample_period(struct xe_gt *gt)
>> return value;
>> }
>>
>> +static void pf_sched_group_media_slices(struct xe_gt *gt, struct guc_sched_group **groups,
>> + u32 *num_groups)
>> +{
>> + u8 slice_to_group[MAX_MEDIA_SLICES];
>> + u32 vecs_mask = VECS_INSTANCES(gt);
>> + u32 gsc_mask = GSCCS_INSTANCES(gt);
>> + u32 vcs_mask = VCS_INSTANCES(gt);
>> + struct guc_sched_group *values;
>> + struct xe_hw_engine *hwe;
>> + enum xe_hw_engine_id id;
>> + int group = 0;
>> + int slice;
>> +
>> + xe_gt_assert(gt, xe_gt_is_media_type(gt));
>> +
>> + /*
>> + * Post-BMG the matching of video engines to slices changes, so for now
>> + * we don't allow this mode on those platforms.
>> + */
>> + if (gt_to_xe(gt)->info.platform > XE_BATTLEMAGE)
>> + return;
>> +
>> + /*
>> + * On BMG and older platforms a media slice has 2 VCS and a VECS. We
>> + * bundle the GSC with the first slice.
>> + */
>> + for (slice = 0; slice < MAX_MEDIA_SLICES; slice++) {
>> + if ((vcs_mask & 0x3) || (vecs_mask & 0x1) || (gsc_mask & 0x1))
>> + slice_to_group[slice] = group++;
>> +
>> + vcs_mask >>= 2;
>> + vecs_mask >>= 1;
>> + gsc_mask >>= 1;
>> + }
>> +
>> + xe_gt_assert(gt, !vcs_mask);
>> + xe_gt_assert(gt, !vecs_mask);
>> + xe_gt_assert(gt, !gsc_mask);
>> +
>> + /* We need at least 2 slices to split them up */
>> + if (group < 2)
>> + return;
>> +
>> + /* The GuC expects an array with a guc_sched_group entry for each group */
>> + values = drmm_kcalloc(>_to_xe(gt)->drm, group, sizeof(struct guc_sched_group),
>> + GFP_KERNEL);
>> + if (!values)
>> + return;
>> +
>> + for_each_hw_engine(hwe, gt, id) {
>> + u8 guc_class = xe_engine_class_to_guc_class(hwe->class);
>> +
>> + switch (hwe->class) {
>> + case XE_ENGINE_CLASS_VIDEO_DECODE:
>> + slice = hwe->instance / 2;
>> + break;
>> + case XE_ENGINE_CLASS_VIDEO_ENHANCE:
>> + slice = hwe->instance;
>> + break;
>> + case XE_ENGINE_CLASS_OTHER:
>> + slice = 0;
>> + break;
>> + default:
>> + xe_gt_assert_msg(gt, false,
>> + "unknown media gt class %u (%s) during EGS setup\n",
>> + hwe->class, hwe->name);
>> + slice = 0;
>> + }
>> +
>> + values[slice_to_group[slice]].engines[guc_class] |= BIT(hwe->logical_instance);
>> + }
>> +
>> + *groups = values;
>> + *num_groups = group;
>> +}
>> +
>> +/**
>> + * xe_sriov_gt_pf_policy_has_sched_groups_support() - Checks whether scheduler
>> + * groups are supported.
>> + * @gt: the &xe_gt
>> + *
>> + * This function can only be called on PF.
>> + *
>> + * Return: true if scheduler groups are supported, false otherwise.
>> + */
>> +bool xe_sriov_gt_pf_policy_has_sched_groups_support(struct xe_gt *gt)
>> +{
>> + xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
>> +
>> + /*
>> + * The GuC supports scheduler groups from v70.53.0, but a fix for it has
>> + * been merged in v70.55.1, so we require the latter. The feature is
>> + * also only enabled on BMG and newer FW.
>> + */
>> + return GUC_FIRMWARE_VER(>->uc.guc) >= MAKE_GUC_VER(70, 55, 1) &&
>> + gt_to_xe(gt)->info.platform >= XE_BATTLEMAGE;
>> +}
>> +
>> +static void pf_init_sched_groups(struct xe_gt *gt)
>> +{
>> + int m;
>> +
>> + if (!xe_sriov_gt_pf_policy_has_sched_groups_support(gt))
>> + return;
>> +
>> + for (m = 0; m < XE_SRIOV_SCHED_GROUPS_MODES_COUNT; m++) {
>> + u32 *num_groups = >->sriov.pf.policy.guc.sched_groups.modes[m].num_groups;
>> + struct guc_sched_group **groups =
>> + >->sriov.pf.policy.guc.sched_groups.modes[m].groups;
>> +
>> + switch (m) {
>> + case XE_SRIOV_SCHED_GROUPS_DISABLED:
>> + break;
> nit: since we know that for DISABLED we have nothing to do in this loop,
> so maybe we should not start with it?
>
> for (m = XE_SRIOV_SCHED_GROUPS_DISABLED + 1, ...
> for (m = XE_SRIOV_SCHED_GROUPS_DISABLED; ++m < ...
>
>
>> + case XE_SRIOV_SCHED_GROUPS_MEDIA_SLICES:
>> + /* this mode only has groups on the media GT */
>> + if (xe_gt_is_media_type(gt))
>> + pf_sched_group_media_slices(gt, groups, num_groups);
>> + break;
>> + default:
> nit: since XE_SRIOV_SCHED_GROUPS are defined as enum, then if we declare 'm' as enum,
> instead of this 'default' case we could just have dummy case for COUNT
> and compiler will help us catch any new missed GROUP mode
>
>> + xe_gt_assert_msg(gt, false, "unknown sched group mode %u\n", m);
>> + return;
> hmm, IIRC those modes are supposed to be per device, not per-GT,
> so there is a high chance that in this loop we will have to handle non-media modes,
> so maybe this assert and early return is too much?
This code is not media-specific. If we have a non media mode we'll just
have to do:
case XE_SRIOV_SCHED_GROUPS_NEW_MODE
if(!xe_gt_is_media_type(gt))
fill_masks_for_new_mode(gt, groups, num_groups);
break;
And that'll work. The return is only in the case where we have a
programming error and the mode has not correctly been added to the
switch. I can still drop the return and leave just the assert, or move
as you said to use the enum for m so that the compiler will catch the
missing case.
>
>> + }
>> +
>> + xe_gt_assert(gt, *num_groups < GUC_MAX_SCHED_GROUPS);
>> + }
>> +}
>> +
>> static void pf_sanitize_guc_policies(struct xe_gt *gt)
>> {
>> pf_sanitize_sched_if_idle(gt);
>> @@ -401,6 +531,18 @@ int xe_gt_sriov_pf_policy_reprovision(struct xe_gt *gt, bool reset)
>> return err ? -ENXIO : 0;
>> }
>>
>> +/**
>> + * xe_gt_sriov_pf_policy_init() - Initializes the SW state of the PF policies.
>> + * @gt: the &xe_gt
>> + *
>> + * This function can only be called on PF. This function does not touch the HW,
>> + * but must be called after the engines have been initialized.
>> + */
>> +void xe_gt_sriov_pf_policy_init(struct xe_gt *gt)
>> +{
>> + pf_init_sched_groups(gt);
>> +}
>> +
>> static void print_guc_policies(struct drm_printer *p, struct xe_gt_sriov_guc_policies *policy)
>> {
>> drm_printf(p, "%s:\t%s\n",
>> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.h
>> index 2a5dc33dc6d7..f5e3b2595063 100644
>> --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.h
>> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.h
>> @@ -17,7 +17,9 @@ int xe_gt_sriov_pf_policy_set_reset_engine(struct xe_gt *gt, bool enable);
>> bool xe_gt_sriov_pf_policy_get_reset_engine(struct xe_gt *gt);
>> int xe_gt_sriov_pf_policy_set_sample_period(struct xe_gt *gt, u32 value);
>> u32 xe_gt_sriov_pf_policy_get_sample_period(struct xe_gt *gt);
>> +bool xe_sriov_gt_pf_policy_has_sched_groups_support(struct xe_gt *gt);
>>
>> +void xe_gt_sriov_pf_policy_init(struct xe_gt *gt);
>> void xe_gt_sriov_pf_policy_sanitize(struct xe_gt *gt);
>> int xe_gt_sriov_pf_policy_reprovision(struct xe_gt *gt, bool reset);
>> int xe_gt_sriov_pf_policy_print(struct xe_gt *gt, struct drm_printer *p);
>> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy_types.h
>> index 4de532af135e..d228cadcd8b0 100644
>> --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy_types.h
>> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy_types.h
>> @@ -8,16 +8,49 @@
>>
>> #include <linux/types.h>
>>
>> +#include "abi/guc_scheduler_abi.h"
>> +
>> +/**
>> + * enum xe_sriov_sched_group_modes - list of possible scheduler group modes
>> + * @XE_SRIOV_SCHED_GROUPS_DISABLED - no separate groups (i.e., all engines in group 0)
>> + * @XE_SRIOV_SCHED_GROUPS_MEDIA_SLICES - separate groups for each media slice
>> + * @XE_SRIOV_SCHED_GROUPS_MODES_COUNT - number of valid modes
>> + */
>> +enum xe_sriov_sched_group_modes {
>> + XE_SRIOV_SCHED_GROUPS_DISABLED = 0,
>> + XE_SRIOV_SCHED_GROUPS_MEDIA_SLICES,
>> + XE_SRIOV_SCHED_GROUPS_MODES_COUNT
> nit: maybe to emphasize that COUNT enumerator is not a real group mode, prefix it with underscore ?
>
> __XE_SRIOV_SCHED_GROUPS_MODES_COUNT /* must be last */
I can add the comment, but I'd prefer not to add the underscore at the
front, since it is pretty clear that this is not a real mode anyway.
Daniele
>
>> +};
>> +
>> +/**
>> + * struct xe_gt_sriov_scheduler_groups - Scheduler groups policy info
>> + * @modes: array of masks and their number for each mode
>> + * @modes.groups: array of engine instance groups in given mode, with each group
>> + * consisting of GUC_MAX_ENGINE_CLASSES engine instances masks. A
>> + * A NULL value indicates that all the engines are in the same
>> + * group for this mode on this GT.
>> + * @modes.num_groups: number of groups in given mode, zero if all the engines
>> + * are in the same group.
>> + */
>> +struct xe_gt_sriov_scheduler_groups {
>> + struct {
>> + struct guc_sched_group *groups;
>> + u32 num_groups;
>> + } modes[XE_SRIOV_SCHED_GROUPS_MODES_COUNT];
>> +};
>> +
>> /**
>> * struct xe_gt_sriov_guc_policies - GuC SR-IOV policies.
>> * @sched_if_idle: controls strict scheduling policy.
>> * @reset_engine: controls engines reset on VF switch policy.
>> * @sample_period: adverse events sampling period (in milliseconds).
>> + * @sched_groups: available scheduling group configurations.
>> */
>> struct xe_gt_sriov_guc_policies {
>> bool sched_if_idle;
>> bool reset_engine;
>> u32 sample_period;
>> + struct xe_gt_sriov_scheduler_groups sched_groups;
>> };
>>
>> /**
> mostly nits, so
>
> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
>
>
next prev parent reply other threads:[~2025-12-11 22:55 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-11 1:56 [PATCH v3 00/12] Introduce SRIOV scheduler groups Daniele Ceraolo Spurio
2025-12-11 1:57 ` [PATCH v3 01/12] drm/xe/gt: Add engine masks for each class Daniele Ceraolo Spurio
2025-12-11 18:19 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 02/12] drm/gt/guc: extract scheduler-related defines from guc_fwif.h Daniele Ceraolo Spurio
2025-12-11 18:20 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 03/12] drm/xe/sriov: Initialize scheduler groups Daniele Ceraolo Spurio
2025-12-11 18:52 ` Michal Wajdeczko
2025-12-11 22:55 ` Daniele Ceraolo Spurio [this message]
2025-12-11 1:57 ` [PATCH v3 04/12] drm/xe/sriov: Add support for enabling " Daniele Ceraolo Spurio
2025-12-11 18:59 ` Michal Wajdeczko
2025-12-11 23:00 ` Daniele Ceraolo Spurio
2025-12-11 1:57 ` [PATCH v3 05/12] drm/xe/sriov: Scheduler groups are incompatible with multi-lrc Daniele Ceraolo Spurio
2025-12-11 19:05 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 06/12] drm/xe/sriov: Add handling for MLRC adverse event threshold Daniele Ceraolo Spurio
2025-12-11 23:19 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 07/12] drm/xe/sriov: Add debugfs to enable scheduler groups Daniele Ceraolo Spurio
2025-12-11 21:07 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 08/12] drm/xe/sriov: Add debugfs with scheduler groups information Daniele Ceraolo Spurio
2025-12-11 22:40 ` Michal Wajdeczko
2025-12-11 22:44 ` Daniele Ceraolo Spurio
2025-12-11 1:57 ` [PATCH v3 09/12] drm/xe/sriov: Prep for multiple exec quantums and preemption timeouts Daniele Ceraolo Spurio
2025-12-11 22:41 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 10/12] drm/xe/sriov: Add functions to set exec quantums for each group Daniele Ceraolo Spurio
2025-12-11 22:47 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 11/12] drm/xe/sriov: Add functions to set preempt timeouts " Daniele Ceraolo Spurio
2025-12-11 22:49 ` Michal Wajdeczko
2025-12-11 1:57 ` [PATCH v3 12/12] drm/xe/sriov: Add debugfs to set EQ and PT for scheduler groups Daniele Ceraolo Spurio
2025-12-11 23:07 ` Michal Wajdeczko
2025-12-11 2:31 ` ✗ CI.checkpatch: warning for Introduce SRIOV scheduler groups (rev3) Patchwork
2025-12-11 2:32 ` ✓ CI.KUnit: success " Patchwork
2025-12-11 3:34 ` ✓ Xe.CI.BAT: " Patchwork
2025-12-11 10:47 ` ✗ Xe.CI.Full: failure " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5fa62765-a018-4712-b966-c8eca9b3cb2b@intel.com \
--to=daniele.ceraolospurio@intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=michal.wajdeczko@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox