drm/xe/configfs: Add enable_multi_queue attribute

Add a new configfs boolean attribute 'enable_multi_queue' that lets an
administrator force-disable multi-queue support on a device before it
binds to the driver. The attribute defaults to true (use the platform
hardware capability as-is); writing 0 force-disables multi-queue. This
is intended for debugging and for validating non-multi-queue code paths
on hardware that would otherwise expose multi-queue.

The override disables multi-queue at two levels:

- UAPI: In alloc_primary_gt(), clear
  gt->info.multi_queue_engine_class_mask on the primary GT so that
  xe_gt_supports_multi_queue() returns false and attempts to create
  a multi-queue group via DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP
  are rejected.

- GuC: In guc_ctl_feature_flags(), set the GUC_CTL_DISABLE_MULTI_QUEUE
  (BIT(24)) init-params bit on GuC firmware older than 70.66. On GuC
  firmware 70.66 and above, guc_waklv_init() emits the new
  GUC_FEATURE_KLV_DISABLE_MULTI_QUEUE Feature KLV (0x5001) via the ADS
  WA/Feature KLV buffer instead. Feature KLVs share the WA KLV buffer.

The attribute is rejected after the device has been bound, so it only
takes effect during probe:

	# echo 0 > /sys/kernel/config/xe/0000:03:00.0/enable_multi_queue
	# echo 0000:03:00.0 > /sys/bus/pci/drivers/xe/bind

v2: Add log for multi-queue disabled. (Niranjana)
v3: Rename attribute to enable_multi_queue with default true. (Stuart &&
    Niranjana)
v4: rebase.

Assisted-by: Claude:claude-opus-4.7
Cc: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Reviewed-by: Stuart Summers <stuart.summers@intel.com>
Link: https://patch.msgid.link/20260709200822.3257825-1-shuicheng.lin@intel.com
Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
This commit is contained in:
Shuicheng Lin 2026-07-09 20:08:22 +00:00
parent ed5a093c2f
commit 73c5a25306
7 changed files with 97 additions and 1 deletions

View File

@ -508,9 +508,10 @@ enum {
#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:
* Feature and Workaround keys:
*/
enum xe_guc_klv_ids {
GUC_FEATURE_KLV_DISABLE_MULTI_QUEUE = 0x5001,
GUC_WORKAROUND_KLV_BLOCK_INTERRUPTS_WHEN_MGSR_BLOCKED = 0x9002,
GUC_WORKAROUND_KLV_DISABLE_PSMI_INTERRUPTS_AT_C6_ENTRY_RESTORE_AT_EXIT = 0x9004,
GUC_WORKAROUND_KLV_ID_GAM_PFQ_SHADOW_TAIL_POLLING = 0x9005,

View File

@ -237,6 +237,18 @@
*
* This setting only takes effect when probing the device.
*
* Enable multi-queue
* ------------------
*
* Multi-queue support on the device is enabled by default where the
* hardware supports it. Writing 0 force-disables multi-queue support:
* multi-queue exec-queue group creation via ioctl is refused, and the
* GuC feature is disabled::
*
* # echo 0 > /sys/kernel/config/xe/0000:03:00.0/enable_multi_queue
*
* This attribute can only be set before binding to the device.
*
* Remove devices
* ==============
*
@ -262,6 +274,7 @@ struct xe_config_group_device {
struct wa_bb ctx_restore_mid_bb[XE_ENGINE_CLASS_MAX];
bool survivability_mode;
bool enable_psmi;
bool enable_multi_queue;
struct {
unsigned int max_vfs;
bool admin_only_pf;
@ -281,6 +294,7 @@ static const struct xe_config_device device_defaults = {
.engines_allowed = U64_MAX,
.survivability_mode = false,
.enable_psmi = false,
.enable_multi_queue = true,
.sriov = {
.max_vfs = XE_DEFAULT_MAX_VFS,
.admin_only_pf = XE_DEFAULT_ADMIN_ONLY_PF,
@ -575,6 +589,33 @@ static ssize_t enable_psmi_store(struct config_item *item, const char *page, siz
return len;
}
static ssize_t enable_multi_queue_show(struct config_item *item, char *page)
{
struct xe_config_device *dev = to_xe_config_device(item);
return sprintf(page, "%d\n", dev->enable_multi_queue);
}
static ssize_t enable_multi_queue_store(struct config_item *item, const char *page,
size_t len)
{
struct xe_config_group_device *dev = to_xe_config_group_device(item);
bool val;
int ret;
ret = kstrtobool(page, &val);
if (ret)
return ret;
guard(mutex)(&dev->lock);
if (is_bound(dev))
return -EBUSY;
dev->config.enable_multi_queue = val;
return len;
}
static bool wa_bb_read_advance(bool dereference, char **p,
const char *append, size_t len,
size_t *max_size)
@ -812,6 +853,7 @@ static ssize_t ctx_restore_post_bb_store(struct config_item *item,
CONFIGFS_ATTR(, ctx_restore_mid_bb);
CONFIGFS_ATTR(, ctx_restore_post_bb);
CONFIGFS_ATTR(, enable_multi_queue);
CONFIGFS_ATTR(, enable_psmi);
CONFIGFS_ATTR(, engines_allowed);
CONFIGFS_ATTR(, gt_types_allowed);
@ -820,6 +862,7 @@ CONFIGFS_ATTR(, survivability_mode);
static struct configfs_attribute *xe_config_device_attrs[] = {
&attr_ctx_restore_mid_bb,
&attr_ctx_restore_post_bb,
&attr_enable_multi_queue,
&attr_enable_psmi,
&attr_engines_allowed,
&attr_gt_types_allowed,
@ -1097,6 +1140,7 @@ static void dump_custom_dev_config(struct pci_dev *pdev,
PRI_CUSTOM_ATTR("%llx", gt_types_allowed);
PRI_CUSTOM_ATTR("%llx", engines_allowed);
PRI_CUSTOM_ATTR("%d", enable_multi_queue);
PRI_CUSTOM_ATTR("%d", enable_psmi);
PRI_CUSTOM_ATTR("%d", survivability_mode);
PRI_CUSTOM_ATTR("%u", sriov.admin_only_pf);
@ -1225,6 +1269,27 @@ bool xe_configfs_get_psmi_enabled(struct pci_dev *pdev)
return ret;
}
/**
* xe_configfs_get_enable_multi_queue - get configfs enable_multi_queue setting
* @pdev: pci device
*
* Return: true if multi-queue is enabled for this device (the default),
* false if it has been force-disabled via configfs.
*/
bool xe_configfs_get_enable_multi_queue(struct pci_dev *pdev)
{
struct xe_config_group_device *dev = find_xe_config_group_device(pdev);
bool ret;
if (!dev)
return true;
ret = dev->config.enable_multi_queue;
config_group_put(&dev->group);
return ret;
}
/**
* xe_configfs_get_ctx_restore_mid_bb - get configfs ctx_restore_mid_bb setting
* @pdev: pci device

View File

@ -23,6 +23,7 @@ bool xe_configfs_primary_gt_allowed(struct pci_dev *pdev);
bool xe_configfs_media_gt_allowed(struct pci_dev *pdev);
u64 xe_configfs_get_engines_allowed(struct pci_dev *pdev);
bool xe_configfs_get_psmi_enabled(struct pci_dev *pdev);
bool xe_configfs_get_enable_multi_queue(struct pci_dev *pdev);
u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev,
enum xe_engine_class class,
const u32 **cs);
@ -42,6 +43,7 @@ static inline bool xe_configfs_primary_gt_allowed(struct pci_dev *pdev) { return
static inline bool xe_configfs_media_gt_allowed(struct pci_dev *pdev) { return true; }
static inline u64 xe_configfs_get_engines_allowed(struct pci_dev *pdev) { return U64_MAX; }
static inline bool xe_configfs_get_psmi_enabled(struct pci_dev *pdev) { return false; }
static inline bool xe_configfs_get_enable_multi_queue(struct pci_dev *pdev) { return true; }
static inline u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev,
enum xe_engine_class class,
const u32 **cs) { return 0; }

View File

@ -102,6 +102,14 @@ static u32 guc_ctl_feature_flags(struct xe_guc *guc)
if (xe_device_is_l2_flush_optimized(xe) && xe_gt_is_media_type(guc_to_gt(guc)))
flags |= GUC_CTL_ENABLE_L2FLUSH_OPT;
/*
* On GuC firmware 70.66 and above, the GUC_FEATURE_KLV_DISABLE_MULTI_QUEUE
* Feature KLV is used instead.
*/
if (!xe_configfs_get_enable_multi_queue(to_pci_dev(xe->drm.dev)) &&
!GUC_FIRMWARE_VER_AT_LEAST(guc, 70, 66))
flags |= GUC_CTL_DISABLE_MULTI_QUEUE;
return flags;
}

View File

@ -16,6 +16,7 @@
#include "regs/xe_gt_regs.h"
#include "regs/xe_guc_regs.h"
#include "xe_bo.h"
#include "xe_configfs.h"
#include "xe_gt.h"
#include "xe_gt_ccs_mode.h"
#include "xe_gt_mcr.h"
@ -402,6 +403,19 @@ static void guc_waklv_init(struct xe_guc_ads *ads)
guc_waklv_enable(ads, NULL, 0, &offset, &remain,
GUC_WA_KLV_IGNORE_MMIO_READ_SEM_TOKEN_64);
/*
* On GuC firmware 70.66 and above, use the Feature KLV (shared with the
* WA KLV buffer); older firmware uses GUC_CTL_DISABLE_MULTI_QUEUE in
* the init params instead.
*/
if (!xe_configfs_get_enable_multi_queue(to_pci_dev(gt_to_xe(gt)->drm.dev)) &&
GUC_FIRMWARE_VER_AT_LEAST(&gt->uc.guc, 70, 66)) {
u32 data = 1;
guc_waklv_enable(ads, &data, 1, &offset, &remain,
GUC_FEATURE_KLV_DISABLE_MULTI_QUEUE);
}
size = guc_ads_waklv_size(ads) - remain;
if (!size)
return;

View File

@ -68,6 +68,7 @@ struct guc_update_exec_queue_policy {
#define GUC_CTL_MAIN_GAMCTRL_QUEUES BIT(9)
#define GUC_CTL_DISABLE_SCHEDULER BIT(14)
#define GUC_CTL_ENABLE_L2FLUSH_OPT BIT(15)
#define GUC_CTL_DISABLE_MULTI_QUEUE BIT(24)
#define GUC_CTL_DEBUG 3
#define GUC_LOG_VERBOSITY REG_GENMASK(1, 0)

View File

@ -22,6 +22,7 @@
#include "xe_device.h"
#include "xe_drv.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_sriov_vf.h"
#include "xe_guc.h"
#include "xe_mmio.h"
@ -888,6 +889,10 @@ static struct xe_gt *alloc_primary_gt(struct xe_tile *tile,
gt->info.has_uncorrectable_error_reporting =
graphics_desc->has_uncorrectable_error_reporting;
gt->info.multi_queue_engine_class_mask = graphics_desc->multi_queue_engine_class_mask;
if (!xe_configfs_get_enable_multi_queue(to_pci_dev(xe->drm.dev))) {
xe_gt_info(gt, "Multi-queue disabled via configfs\n");
gt->info.multi_queue_engine_class_mask = 0;
}
gt->info.engine_mask = graphics_desc->hw_engine_mask;
gt->info.num_geometry_xecore_fuse_regs = graphics_desc->num_geometry_xecore_fuse_regs;
gt->info.num_compute_xecore_fuse_regs = graphics_desc->num_compute_xecore_fuse_regs;