Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Gustavo Sousa <gustavo.sousa@intel.com>
To: Varun Gupta <varun.gupta@intel.com>, <intel-xe@lists.freedesktop.org>
Cc: <matthew.d.roper@intel.com>, <stuart.summers@intel.com>
Subject: Re: [PATCH v7] drm/xe: Add debugfs knob to control GPGPU preemption granularity
Date: Wed, 15 Jul 2026 18:27:31 -0300	[thread overview]
Message-ID: <87ech46j0c.fsf@intel.com> (raw)
In-Reply-To: <20260714115926.3038446-1-varun.gupta@intel.com>

Varun Gupta <varun.gupta@intel.com> writes:

> Introduce a per-GT debugfs knob, 'gpgpu_preemption_level', to allow
> overriding the GPGPU preemption level on a per-context basis for newly
> created LRCs.
> Add an RTP rule to enable per-context control via FF_SLICE_CS_CHICKEN1,
> allowing the preemption level to be programmed directly into the LRC
> image at CTX_CS_CHICKEN1 during context initialization.
>
> v7:
>   - Restrict XEHP_FUSE4 read to Xe2+ primary GTs to prevent invalid
>     Media GT accesses and SR-IOV warnings. (Sashiko)
>
> v6:
>   - Add missing xe_gt_printk.h include to fix compilation failure.
>
> v5:
>   - Use correct offset for CTX_CS_CHICKEN1. (Matt)
>   - Restrict to the RCS engine. (Matt)
>   - Drop LRC layout table modifications; dummy layouts do not need late
>     context registers. (Matt)
>   - Stash WMTP fuse state at boot to remove pm/forcewake from debugfs.
>     (Matt)
>   - Rename debugfs knob to 'gpgpu_preemption_level'. (Matt)
>   - Use simple_write_to_buffer() and remove unnecessary READ_ONCE/
>     WRITE_ONCE macros. (Matt)
>   - Do not restrict debugfs visibility for SR-IOV VFs. (Matt)
>
> v4
>   - Fix incorrect NOP padding in the RCS context layout. (Sashiko)
>
> v3:
>   - Wrapped XEHP_FUSE4 forcewake read with xe_pm_runtime_get/put to
>     prevent PCIe aborts/timeouts when the GPU is in D3hot/D3cold. (sashiko)
>   - Fixed NOP macro truncation by splitting padding offsets larger than
>     0x7f into multiple NOPs, ensuring correct context layout. (sashiko)
>   - Converted CTX_CS_CHICKEN1 initialization to a read-modify-write
>     sequence to avoid overwriting golden context mask bits. (sashiko)
>   - Removed the FF_SLICE_CS_CHICKEN1 workaround for CCS engines, as
>     compute engines lack this 3D fixed-function register, which was
>     causing GuC "illegal register" panics on initialization.
>
> v2:
>   - Dropped the WA BB/MI_LRI path; per Bspec, CS_CHICKEN1 is context
>     save/restore state at DW 0x00E2, so we map CTX_CS_CHICKEN1 and program
>     it directly in LRC init via xe_lrc_write_ctx_reg(). (Matt)
>   - Split Xe2 CCS context offsets into a dedicated xe2_ccs_offsets array
>     to map CS_CHICKEN1 without polluting other XCS engines.
>   - Converted the debugfs interface from a binary boolean to a
>     multi-option string knob ("default", "mid-thread", "thread-group",
>     "command"). (Gustavo)
>   - Restricted file creation to the Physical Function
>     (!IS_SRIOV_VF). (Gustavo)
>   - Added kernel tainting (TAINT_USER) when deviating from
>     defaults. (Gustavo)
>   - Added power-safe hardware fuse check (FUSE4 register 0x9114[20],
>     CFEG_WMTP_DISABLE) before allowing MTP selection. (Matt)
>
> Signed-off-by: Varun Gupta <varun.gupta@intel.com>
> ---
>  drivers/gpu/drm/xe/regs/xe_lrc_layout.h |  2 +
>  drivers/gpu/drm/xe/xe_gt.c              |  5 ++
>  drivers/gpu/drm/xe/xe_gt_debugfs.c      | 65 +++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_gt_types.h        | 34 +++++++++++++
>  drivers/gpu/drm/xe/xe_lrc.c             | 29 +++++++++++
>  drivers/gpu/drm/xe/xe_wa.c              |  6 +++
>  6 files changed, 141 insertions(+)
>
> diff --git a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h
> index 4ab86fc369fd..6f7abc0181b5 100644
> --- a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h
> +++ b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h
> @@ -37,6 +37,8 @@
>  #define CTX_QUEUE_TIMESTAMP		(0xd0 + 1)
>  #define CTX_QUEUE_TIMESTAMP_UDW		(0xd2 + 1)
>  
> +#define CTX_CS_CHICKEN1			(0x12e + 1)
> +
>  #define INDIRECT_CTX_RING_HEAD		(0x02 + 1)
>  #define INDIRECT_CTX_RING_TAIL		(0x04 + 1)
>  #define INDIRECT_CTX_RING_START		(0x06 + 1)
> diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c
> index 783eb6d631b5..688cadb9b589 100644
> --- a/drivers/gpu/drm/xe/xe_gt.c
> +++ b/drivers/gpu/drm/xe/xe_gt.c
> @@ -607,6 +607,11 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt)
>  	 * on pre-MTL platforms, reading it there will (correctly) return 0.
>  	 */
>  	gt->info.gmdid = xe_mmio_read32(&gt->mmio, GMD_ID);

Nitpick: Maybe add a blank line here to dissociate initialization of
has_wmtp_disabled from the comment about GMD_ID above.

> +	if (GRAPHICS_VER(gt_to_xe(gt)) >= 20 && xe_gt_is_main_type(gt))
> +		gt->info.has_wmtp_disabled = !!(xe_mmio_read32(&gt->mmio, XEHP_FUSE4) &
> +			CFEG_WMTP_DISABLE);

I think Matt's suggestion was to stash the value of XEHP_FUSE4 and use
it whenever necessary (there are other users).  But I guess keeping a
has_wmtp_disabled member like done in this patch is fine as well.  We
could do the former in a separate patch if we find it useful (we would
need to check if we would need to deal with other fuse registers as
well).

> +	else
> +		gt->info.has_wmtp_disabled = 0;
>  
>  	/*
>  	 * Wa_14026539277 can't be implemented as a regular GT workaround (i.e.
> diff --git a/drivers/gpu/drm/xe/xe_gt_debugfs.c b/drivers/gpu/drm/xe/xe_gt_debugfs.c
> index c38bcacb27e4..288590003461 100644
> --- a/drivers/gpu/drm/xe/xe_gt_debugfs.c
> +++ b/drivers/gpu/drm/xe/xe_gt_debugfs.c
> @@ -6,6 +6,8 @@
>  #include "xe_gt_debugfs.h"
>  
>  #include <linux/debugfs.h>
> +#include <linux/panic.h>
> +#include <linux/string.h>
>  
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_managed.h>
> @@ -15,6 +17,7 @@
>  #include "xe_gt.h"
>  #include "xe_gt_mcr.h"
>  #include "xe_gt_idle.h"
> +#include "xe_gt_printk.h"
>  #include "xe_gt_sriov_pf_debugfs.h"
>  #include "xe_gt_sriov_vf_debugfs.h"
>  #include "xe_gt_stats.h"
> @@ -336,6 +339,65 @@ static int force_reset_sync_show(struct seq_file *s, void *unused)
>  }
>  DEFINE_SHOW_STORE_ATTRIBUTE(force_reset_sync);
>  
> +static const char * const gpgpu_preemption_level_names[] = {
> +	[XE_GPGPU_PREEMPT_DEFAULT]      = "default",
> +	[XE_GPGPU_PREEMPT_MID_THREAD]   = "mid-thread",
> +	[XE_GPGPU_PREEMPT_THREAD_GROUP] = "thread-group",
> +	[XE_GPGPU_PREEMPT_COMMAND]      = "command",
> +};
> +
> +static int gpgpu_preemption_level_show(struct seq_file *m, void *unused)
> +{
> +	struct xe_gt *gt = m->private;
> +
> +	seq_printf(m, "%s\n", gpgpu_preemption_level_names[gt->gpgpu_preemption_level]);
> +
> +	return 0;
> +}
> +
> +static ssize_t gpgpu_preemption_level_write(struct file *file,
> +					    const char __user *ubuf,
> +					    size_t len, loff_t *offp)
> +{
> +	struct seq_file *m = file->private_data;
> +	struct xe_gt *gt = m->private;
> +	enum xe_gpgpu_preempt_level new_level;
> +	char buf[16];
> +	ssize_t copied;
> +	int idx;
> +
> +	if (*offp)
> +		return -EINVAL;
> +
> +	copied = simple_write_to_buffer(buf, sizeof(buf) - 1, offp, ubuf, len);
> +	if (copied < 0)
> +		return copied;
> +
> +	buf[copied] = '\0';
> +	idx = sysfs_match_string(gpgpu_preemption_level_names, strim(buf));
> +	if (idx < 0)
> +		return idx;
> +
> +	new_level = (enum xe_gpgpu_preempt_level)idx;
> +
> +	if (new_level == XE_GPGPU_PREEMPT_MID_THREAD && gt->info.has_wmtp_disabled) {
> +		xe_gt_warn(gt, "MTP fused off in hardware, cannot select mid-thread\n");
> +		return -EPERM;

I think we should just return -EINVAL here as well with the rationale
that "mid-thread" is an invalid value for the current hardware.

> +	}
> +
> +	if (new_level != XE_GPGPU_PREEMPT_DEFAULT) {
> +		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
> +		xe_gt_notice(gt,
> +			     "GPGPU preemption overridden to '%s' (applies to new LRCs only)\n",
> +			     gpgpu_preemption_level_names[new_level]);
> +	}
> +
> +	gt->gpgpu_preemption_level = new_level;
> +
> +	return copied;
> +}
> +DEFINE_SHOW_STORE_ATTRIBUTE(gpgpu_preemption_level);
> +
>  void xe_gt_debugfs_register(struct xe_gt *gt)
>  {
>  	struct xe_device *xe = gt_to_xe(gt);
> @@ -368,6 +430,9 @@ void xe_gt_debugfs_register(struct xe_gt *gt)
>  	debugfs_create_file("stats", 0600, root, gt, &stats_fops);
>  	debugfs_create_file("force_reset", 0600, root, gt, &force_reset_fops);
>  	debugfs_create_file("force_reset_sync", 0600, root, gt, &force_reset_sync_fops);

Nitpick: Maybe add an blank line here.

> +	if (GRAPHICS_VER(xe) >= 20 && (gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK))
> +		debugfs_create_file("gpgpu_preemption_level", 0600, root,
> +				    gt, &gpgpu_preemption_level_fops);
>  
>  	drm_debugfs_create_files(vf_safe_debugfs_list,
>  				 ARRAY_SIZE(vf_safe_debugfs_list),
> diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
> index e5588c88800a..97bd943309b3 100644
> --- a/drivers/gpu/drm/xe/xe_gt_types.h
> +++ b/drivers/gpu/drm/xe/xe_gt_types.h
> @@ -35,6 +35,33 @@ enum xe_gt_eu_type {
>  	XE_GT_EU_TYPE_SIMD16,
>  };
>  
> +/**
> + * enum xe_gpgpu_preempt_level - Per-context GPGPU preemption override mode
> + *
> + * Selects the preemption granularity programmed into CS_CHICKEN1[2:1] for
> + * newly created Xe2+ RCS LRCs.
> + *
> + * The per-context override is effective only when
> + * FF_SLICE_CS_CHICKEN1[FFSC_PERCTX_PREEMPT_CTRL] is enabled via RTP.
> + *
> + * This setting is GT-scoped and affects only LRCs created after the value is
> + * changed; existing contexts keep their previously programmed value.
> + *
> + * @XE_GPGPU_PREEMPT_DEFAULT: Keep platform default preemption granularity.
> + * @XE_GPGPU_PREEMPT_MID_THREAD: Force mid-thread preemption level.
> + * @XE_GPGPU_PREEMPT_THREAD_GROUP: Force thread-group preemption level.
> + * @XE_GPGPU_PREEMPT_COMMAND: Force command-level preemption.
> + *
> + * Zero-initialized via kzalloc, so XE_GPGPU_PREEMPT_DEFAULT is the safe
> + * default (no override from platform policy).
> + */
> +enum xe_gpgpu_preempt_level {
> +	XE_GPGPU_PREEMPT_DEFAULT = 0,
> +	XE_GPGPU_PREEMPT_MID_THREAD,
> +	XE_GPGPU_PREEMPT_THREAD_GROUP,
> +	XE_GPGPU_PREEMPT_COMMAND,
> +};
> +
>  #define XE_MAX_DSS_FUSE_REGS		4
>  #define XE_MAX_DSS_FUSE_BITS		(32 * XE_MAX_DSS_FUSE_REGS)
>  #define XE_MAX_EU_FUSE_REGS		1
> @@ -151,6 +178,8 @@ struct xe_gt {
>  		 * feature.
>  		 */
>  		u8 has_xe2_blt_instructions:1;
> +		/** @info.has_wmtp_disabled: hardware fuse indicates WMTP is disabled */
> +		u8 has_wmtp_disabled:1;
>  		/**
>  		 * @info.num_geometry_xecore_fuse_regs: Number of 32b-bit fuse
>  		 * registers the geometry XeCore mask spans.
> @@ -219,6 +248,11 @@ struct xe_gt {
>  	 */
>  	u32 ccs_mode;
>  
> +	/**
> +	 * @gpgpu_preemption_level: per-GT GPGPU preemption granularity override.
> +	 */
> +	enum xe_gpgpu_preempt_level gpgpu_preemption_level;
> +
>  	/** @usm: unified shared memory state */
>  	struct {
>  		/**
> diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
> index 3e7c995085d0..1733bbe65288 100644
> --- a/drivers/gpu/drm/xe/xe_lrc.c
> +++ b/drivers/gpu/drm/xe/xe_lrc.c
> @@ -1589,6 +1589,35 @@ static int xe_lrc_ctx_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, struct
>  	if (xe->info.has_asid && vm)
>  		xe_lrc_write_ctx_reg(lrc, CTX_ASID, vm->usm.asid);
>  
> +	if (GRAPHICS_VER(xe) >= 20 && hwe->class == XE_ENGINE_CLASS_RENDER) {
> +		enum xe_gpgpu_preempt_level level = gt->gpgpu_preemption_level;
> +
> +		if (level != XE_GPGPU_PREEMPT_DEFAULT) {
> +			u32 level_bits;
> +			u32 val;
> +
> +			switch (level) {
> +			case XE_GPGPU_PREEMPT_MID_THREAD:
> +				level_bits = PREEMPT_GPGPU_MID_THREAD_LEVEL;
> +				break;
> +			case XE_GPGPU_PREEMPT_THREAD_GROUP:
> +				level_bits = PREEMPT_GPGPU_THREAD_GROUP_LEVEL;
> +				break;
> +			case XE_GPGPU_PREEMPT_COMMAND:
> +				level_bits = PREEMPT_GPGPU_COMMAND_LEVEL;
> +				break;
> +			default:
> +				level_bits = 0;

If we find an unexpected value, it is probably better to have a warning
(e.g. XE_WARN_ON(true))and avoid programming CS_CHICKEN1.

> +				break;
> +			}
> +
> +			val = xe_lrc_read_ctx_reg(lrc, CTX_CS_CHICKEN1);
> +			val &= ~PREEMPT_GPGPU_LEVEL_MASK;
> +			val |= REG_MASKED_FIELD(PREEMPT_GPGPU_LEVEL_MASK, level_bits);
> +			xe_lrc_write_ctx_reg(lrc, CTX_CS_CHICKEN1, val);
> +		}
> +	}
> +

It would be good to encapsulate this into a function, say
xe_lrc_set_gpgpu_preemption_level(), that is called here. It improves
readability and can also simplify the above logic with some early
returns.

>  	lrc->desc = LRC_VALID;
>  	lrc->desc |= FIELD_PREP(LRC_ADDRESSING_MODE, LRC_LEGACY_64B_CONTEXT);
>  	/* TODO: Priority */
> diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c
> index 139434946f8f..70072963aba0 100644
> --- a/drivers/gpu/drm/xe/xe_wa.c
> +++ b/drivers/gpu/drm/xe/xe_wa.c
> @@ -347,6 +347,12 @@ static const struct xe_rtp_table_sr engine_was = XE_RTP_TABLE_SR(
>  	  XE_RTP_ACTIONS(SET(FF_SLICE_CS_CHICKEN1(RENDER_RING_BASE),
>  			     FFSC_PERCTX_PREEMPT_CTRL))
>  	},
> +	{ XE_RTP_NAME("FtrPerCtxtPreemptionGranularityControl-Xe2"),
> +	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED),
> +		       ENGINE_CLASS(RENDER)),
> +	  XE_RTP_ACTIONS(SET(FF_SLICE_CS_CHICKEN1(RENDER_RING_BASE),
> +			     FFSC_PERCTX_PREEMPT_CTRL))
> +	},

We could re-use the "FtrPerCtxtPreemptionGranularityControl" entry by
combining the rules with an "OR":

XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1250), ENGINE_CLASS(RENDER), OR,
             GRAPHICS_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED), ENGINE_CLASS(RENDER))

That said, we are unconditionally changing a hardware default here only
for the sake of having the gpgpu_preemption_level debugfs entry, which
will only be used for debugging scenarios.

I wonder if we should change FFSC_PERCTX_PREEMPT_CTRL only if needed.
Thoughts?

In that case, we could do that via configfs and then this entry would
use FIELD_SET_FUNC() to defined based on the configured value (and the
debugfs entry would also be created conditioned on the configured
value).  In this case, it would make sense to keep this a separate RTP
entry.

Other option would be to try to make the change of
FFSC_PERCTX_PREEMPT_CTRL at runtime at the right places if
gpgpu_preemption_level is set to a non-default value, but I think this
approach is more complex and perhaps the configfs option would be easier
to implement.

--
Gustavo Sousa

>  	{ XE_RTP_NAME("18032247524"),
>  	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2004),
>  		       FUNC(xe_rtp_match_first_render_or_compute)),
> -- 
> 2.43.0

  reply	other threads:[~2026-07-15 21:27 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-18  4:24 [PATCH] drm/xe: Add debugfs knob to disable Mid-Thread Preemption per GT Varun Gupta
2026-06-18  4:31 ` ✓ CI.KUnit: success for " Patchwork
2026-06-18  5:22 ` ✓ Xe.CI.BAT: " Patchwork
2026-06-18 11:05 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-06-18 14:01 ` [PATCH] " Gustavo Sousa
2026-06-18 16:42 ` Matt Roper
2026-07-01 17:58 ` [PATCH] drm/xe: Add debugfs knob to control GPGPU preemption granularity Varun Gupta
2026-07-01 18:19 ` ✓ CI.KUnit: success for drm/xe: Add debugfs knob to disable Mid-Thread Preemption per GT (rev2) Patchwork
2026-07-01 19:11 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-07-02 14:38 ` ✗ Xe.CI.FULL: " Patchwork
2026-07-06  5:35 ` [PATCH v3] drm/xe: Add debugfs knob to control GPGPU preemption granularity Varun Gupta
2026-07-06 12:02 ` ✓ CI.KUnit: success for drm/xe: Add debugfs knob to disable Mid-Thread Preemption per GT (rev3) Patchwork
2026-07-06 12:47 ` ✓ Xe.CI.BAT: " Patchwork
2026-07-06 14:02 ` ✓ Xe.CI.FULL: " Patchwork
2026-07-06 14:12 ` [PATCH v4] drm/xe: Add debugfs knob to control GPGPU preemption granularity Varun Gupta
2026-07-08 21:08   ` Matt Roper
2026-07-06 14:49 ` ✓ CI.KUnit: success for drm/xe: Add debugfs knob to disable Mid-Thread Preemption per GT (rev4) Patchwork
2026-07-06 15:35 ` ✓ Xe.CI.BAT: " Patchwork
2026-07-06 17:31 ` ✓ Xe.CI.FULL: " Patchwork
2026-07-13 13:54 ` [PATCH v5] drm/xe: Add debugfs knob to control GPGPU preemption granularity Varun Gupta
2026-07-13 14:13 ` [PATCH v6] " Varun Gupta
2026-07-13 14:29 ` ✓ CI.KUnit: success for drm/xe: Add debugfs knob to disable Mid-Thread Preemption per GT (rev6) Patchwork
2026-07-13 15:07 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-07-13 18:08 ` ✓ Xe.CI.FULL: success " Patchwork
2026-07-14 11:59 ` [PATCH v7] drm/xe: Add debugfs knob to control GPGPU preemption granularity Varun Gupta
2026-07-15 21:27   ` Gustavo Sousa [this message]
2026-07-14 13:01 ` ✓ CI.KUnit: success for drm/xe: Add debugfs knob to disable Mid-Thread Preemption per GT (rev7) Patchwork
2026-07-14 13:38 ` ✓ Xe.CI.BAT: " Patchwork
2026-07-14 18:50 ` ✓ Xe.CI.FULL: " 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=87ech46j0c.fsf@intel.com \
    --to=gustavo.sousa@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=matthew.d.roper@intel.com \
    --cc=stuart.summers@intel.com \
    --cc=varun.gupta@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