All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
To: Stuart Summers <stuart.summers@intel.com>
Cc: <intel-xe@lists.freedesktop.org>, <fei.yang@intel.com>
Subject: Re: [PATCH 1/1] drm/xe/configfs: Allow overriding the GuC hwconfig table
Date: Wed, 11 Nov 2026 14:37:14 -0500	[thread overview]
Message-ID: <avTD6oXFiZcjPmAg@intel.com> (raw)
In-Reply-To: <20261111000818.238585-4-stuart.summers@intel.com>

On Wed, Nov 11, 2026 at 12:08:18AM +0000, Stuart Summers wrote:
> Add a binary configfs attribute holding a raw hwconfig blob. When set
> before bind, it is loaded into the hwconfig BO instead of querying GuC,
> so all consumers - including the DRM_XE_DEVICE_QUERY_HWCONFIG IOCTL -
> see the override. This also permits supplying a table on platforms where
> GuC exposes none, which is useful for testing userspace against
> hwconfig data the hardware does not report.

we should only put this in after we get that series that make most of
configfs as debug environments only...

> 
> Signed-off-by: Stuart Summers <stuart.summers@intel.com>
> ---
>  drivers/gpu/drm/xe/xe_configfs.c     | 119 ++++++++++++++++++++++++++-
>  drivers/gpu/drm/xe/xe_configfs.h     |   6 ++
>  drivers/gpu/drm/xe/xe_guc_hwconfig.c |  36 +++++---
>  3 files changed, 150 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_configfs.c b/drivers/gpu/drm/xe/xe_configfs.c
> index 2ddd707a6dbd..6f810b33e12d 100644
> --- a/drivers/gpu/drm/xe/xe_configfs.c
> +++ b/drivers/gpu/drm/xe/xe_configfs.c
> @@ -63,7 +63,8 @@
>   *	    ├── engines_allowed
>   *	    ├── migrate_ulls_period_ms
>   *	    ├── enable_psmi
> - *	    └── disable_vram_page_offline
> + *	    ├── disable_vram_page_offline
> + *	    └── hwconfig
>   *
>   * After configuring the attributes as per next section, the device can be
>   * probed with::
> @@ -277,6 +278,22 @@
>   *
>   * This attribute can only be set before binding to the device.
>   *
> + * Hwconfig:
> + * ---------
> + *
> + * Override the hardware configuration table normally obtained from the GuC
> + * with a user-provided binary blob. When set, the driver uses this table in
> + * place of the GuC one everywhere it is consumed, including the table
> + * reported to userspace by the DRM_XE_DEVICE_QUERY_HWCONFIG query. This also
> + * allows a table to be provided on platforms where the GuC exposes none.
> + *
> + * The blob is the raw hwconfig table, so its size must be a multiple of 4
> + * bytes. Writing a new blob replaces the previous one::
> + *
> + *	# cat hwconfig.bin > /sys/kernel/config/xe/0000:03:00.0/hwconfig
> + *
> + * This attribute can only be set before binding to the device.
> + *
>   * Remove devices
>   * ==============
>   *
> @@ -291,6 +308,12 @@ struct wa_bb {
>  	u32 len; /* in dwords */
>  };
>  
> +/* User-provided replacement for the GuC-provided hwconfig table */
> +struct hwconfig_blob {
> +	void *data;
> +	size_t len; /* in bytes */
> +};
> +
>  struct xe_config_group_device {
>  	struct config_group group;
>  	struct config_group sriov;
> @@ -299,6 +322,7 @@ struct xe_config_group_device {
>  		u64 gt_types_allowed;
>  		u64 engines_allowed;
>  		u32 migrate_ulls_period_ms;
> +		struct hwconfig_blob hwconfig;
>  		struct wa_bb ctx_restore_post_bb[XE_ENGINE_CLASS_MAX];
>  		struct wa_bb ctx_restore_mid_bb[XE_ENGINE_CLASS_MAX];
>  		bool survivability_mode;
> @@ -937,6 +961,50 @@ static ssize_t ctx_restore_post_bb_store(struct config_item *item,
>  	return wa_bb_store(dev->config.ctx_restore_post_bb, dev, data, sz);
>  }
>  
> +static ssize_t hwconfig_read(struct config_item *item, void *buf, size_t count)
> +{
> +	struct xe_config_group_device *dev = to_xe_config_group_device(item);
> +
> +	guard(mutex)(&dev->lock);
> +
> +	if (!buf)
> +		return dev->config.hwconfig.len;
> +
> +	count = min(count, dev->config.hwconfig.len);
> +	memcpy(buf, dev->config.hwconfig.data, count);
> +
> +	return count;
> +}
> +
> +static ssize_t hwconfig_write(struct config_item *item, const void *buf, size_t count)
> +{
> +	struct xe_config_group_device *dev = to_xe_config_group_device(item);
> +	void *data = NULL;
> +
> +	/* The table is a sequence of dwords */
> +	if (count % sizeof(u32))
> +		return -EINVAL;
> +
> +	if (count) {
> +		data = kmemdup(buf, count, GFP_KERNEL);
> +		if (!data)
> +			return -ENOMEM;
> +	}
> +
> +	guard(mutex)(&dev->lock);
> +
> +	if (is_bound(dev)) {
> +		kfree(data);
> +		return -EBUSY;
> +	}
> +
> +	kfree(dev->config.hwconfig.data);
> +	dev->config.hwconfig.data = data;
> +	dev->config.hwconfig.len = count;
> +
> +	return count;
> +}
> +
>  CONFIGFS_ATTR(, ctx_restore_mid_bb);
>  CONFIGFS_ATTR(, ctx_restore_post_bb);
>  CONFIGFS_ATTR(, enable_multi_queue);
> @@ -946,6 +1014,7 @@ CONFIGFS_ATTR(, disable_vram_page_offline);
>  CONFIGFS_ATTR(, engines_allowed);
>  CONFIGFS_ATTR(, gt_types_allowed);
>  CONFIGFS_ATTR(, survivability_mode);
> +CONFIGFS_BIN_ATTR(, hwconfig, NULL, SZ_64K);
>  
>  static struct configfs_attribute *xe_config_device_attrs[] = {
>  	&attr_ctx_restore_mid_bb,
> @@ -960,12 +1029,18 @@ static struct configfs_attribute *xe_config_device_attrs[] = {
>  	NULL,
>  };
>  
> +static const struct configfs_bin_attribute *const xe_config_device_bin_attrs[] = {
> +	&attr_hwconfig,
> +	NULL,
> +};
> +
>  static void xe_config_device_release(struct config_item *item)
>  {
>  	struct xe_config_group_device *dev = to_xe_config_group_device(item);
>  
>  	mutex_destroy(&dev->lock);
>  
> +	kfree(dev->config.hwconfig.data);
>  	kfree(dev->config.ctx_restore_mid_bb[0].cs);
>  	kfree(dev->config.ctx_restore_post_bb[0].cs);
>  	kfree(dev);
> @@ -1001,6 +1076,7 @@ static const struct config_item_type xe_config_device_type = {
>  	.ct_item_ops	= &xe_config_device_ops,
>  	.ct_group_ops	= &xe_config_device_group_ops,
>  	.ct_attrs	= xe_config_device_attrs,
> +	.ct_bin_attrs	= xe_config_device_bin_attrs,
>  	.ct_owner	= THIS_MODULE,
>  };
>  
> @@ -1243,6 +1319,10 @@ static void dump_custom_dev_config(struct pci_dev *pdev,
>  	PRI_CUSTOM_ATTR("%u", sriov.admin_only_pf);
>  
>  #undef PRI_CUSTOM_ATTR
> +
> +	if (dev->config.hwconfig.len)
> +		pci_info(pdev, "configfs: hwconfig = %zu bytes\n",
> +			 dev->config.hwconfig.len);
>  }
>  
>  /**
> @@ -1479,6 +1559,43 @@ u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev,
>  	return len;
>  }
>  
> +/**
> + * xe_configfs_get_hwconfig - get a copy of the configfs hwconfig blob
> + * @pdev: pci device
> + * @blob: pointer to store the newly allocated copy of the blob
> + *
> + * If a hwconfig table override was written to configfs for @pdev, allocate a
> + * copy of it and store the pointer in @blob. The caller takes ownership of it
> + * and is responsible for freeing it with kfree().
> + *
> + * Return: size in bytes of the blob stored in @blob, or 0 if no override is
> + *     set or it could not be copied.
> + */
> +size_t xe_configfs_get_hwconfig(struct pci_dev *pdev, void **blob)
> +{
> +	struct xe_config_group_device *dev = find_xe_config_group_device(pdev);
> +	size_t len = 0;
> +
> +	*blob = NULL;
> +
> +	if (!dev)
> +		return 0;
> +
> +	scoped_guard(mutex, &dev->lock) {
> +		if (!dev->config.hwconfig.len)
> +			break;
> +
> +		*blob = kmemdup(dev->config.hwconfig.data,
> +				dev->config.hwconfig.len, GFP_KERNEL);
> +		if (*blob)
> +			len = dev->config.hwconfig.len;
> +	}
> +
> +	config_group_put(&dev->group);
> +
> +	return len;
> +}
> +
>  #ifdef CONFIG_PCI_IOV
>  /**
>   * xe_configfs_admin_only_pf() - Get PF's operational mode.
> diff --git a/drivers/gpu/drm/xe/xe_configfs.h b/drivers/gpu/drm/xe/xe_configfs.h
> index 327b648944ff..526250e9fdfe 100644
> --- a/drivers/gpu/drm/xe/xe_configfs.h
> +++ b/drivers/gpu/drm/xe/xe_configfs.h
> @@ -32,6 +32,7 @@ u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev,
>  u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev,
>  					enum xe_engine_class class,
>  					const u32 **cs);
> +size_t xe_configfs_get_hwconfig(struct pci_dev *pdev, void **blob);
>  #ifdef CONFIG_PCI_IOV
>  unsigned int xe_configfs_get_max_vfs(struct pci_dev *pdev);
>  bool xe_configfs_admin_only_pf(struct pci_dev *pdev);
> @@ -54,6 +55,11 @@ static inline u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev,
>  static inline u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev,
>  						      enum xe_engine_class class,
>  						      const u32 **cs) { return 0; }
> +static inline size_t xe_configfs_get_hwconfig(struct pci_dev *pdev, void **blob)
> +{
> +	*blob = NULL;
> +	return 0;
> +}
>  #ifdef CONFIG_PCI_IOV
>  static inline unsigned int xe_configfs_get_max_vfs(struct pci_dev *pdev)
>  {
> diff --git a/drivers/gpu/drm/xe/xe_guc_hwconfig.c b/drivers/gpu/drm/xe/xe_guc_hwconfig.c
> index dc667a71b438..33abfdfcff41 100644
> --- a/drivers/gpu/drm/xe/xe_guc_hwconfig.c
> +++ b/drivers/gpu/drm/xe/xe_guc_hwconfig.c
> @@ -10,7 +10,9 @@
>  
>  #include "abi/guc_actions_abi.h"
>  #include "xe_bo.h"
> +#include "xe_configfs.h"
>  #include "xe_device_types.h"
> +#include "xe_gt_printk.h"
>  #include "xe_gt_types.h"
>  #include "xe_guc.h"
>  #include "xe_map.h"
> @@ -55,6 +57,7 @@ int xe_guc_hwconfig_init(struct xe_guc *guc)
>  	struct xe_gt *gt = guc_to_gt(guc);
>  	struct xe_tile *tile = gt_to_tile(gt);
>  	struct xe_bo *bo;
> +	void *blob;
>  	u32 size;
>  	int err;
>  
> @@ -68,25 +71,38 @@ int xe_guc_hwconfig_init(struct xe_guc *guc)
>  	if (gt != xe_root_mmio_gt(xe))
>  		return 0;
>  
> -	/* ADL_P, DG2+ supports hwconfig table */
> -	if (GRAPHICS_VERx100(xe) < 1255 && xe->info.platform != XE_ALDERLAKE_P)
> -		return 0;
> -
> -	err = guc_hwconfig_size(guc, &size);
> -	if (err)
> -		return err;
> -	if (!size)
> -		return -EINVAL;
> +	size = xe_configfs_get_hwconfig(to_pci_dev(xe->drm.dev), &blob);
> +	if (!size) {
> +		/* ADL_P, DG2+ supports hwconfig table */
> +		if (GRAPHICS_VERx100(xe) < 1255 && xe->info.platform != XE_ALDERLAKE_P)
> +			return 0;
> +
> +		err = guc_hwconfig_size(guc, &size);
> +		if (err)
> +			return err;
> +		if (!size)
> +			return -EINVAL;
> +	}
>  
>  	bo = xe_managed_bo_create_pin_map(xe, tile, PAGE_ALIGN(size),
>  					  XE_BO_FLAG_SYSTEM |
>  					  XE_BO_FLAG_GGTT |
>  					  XE_BO_FLAG_GGTT_INVALIDATE);
> -	if (IS_ERR(bo))
> +	if (IS_ERR(bo)) {
> +		kfree(blob);
>  		return PTR_ERR(bo);
> +	}
>  	guc->hwconfig.bo = bo;
>  	guc->hwconfig.size = size;
>  
> +	if (blob) {
> +		xe_map_memcpy_to(xe, &bo->vmap, 0, blob, size);
> +		kfree(blob);
> +		xe_gt_info(gt, "Using hwconfig table override from configfs (%u bytes)\n",
> +			   size);
> +		return 0;
> +	}
> +
>  	return guc_hwconfig_copy(guc);
>  }
>  
> -- 
> 2.43.0
> 

  parent reply	other threads:[~2026-11-11 19:37 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11  0:08 [PATCH 0/1] Add a configfs to program the hwconfig Stuart Summers
2026-11-11  0:08 ` [PATCH 1/1] drm/xe/configfs: Allow overriding the GuC hwconfig table Stuart Summers
2026-11-11  0:25   ` sashiko-bot
2026-11-11 19:37   ` Rodrigo Vivi [this message]
2026-11-11  1:35 ` ✓ CI.KUnit: success for Add a configfs to program the hwconfig Patchwork
2026-11-11  2:09 ` ✓ Xe.CI.BAT: " Patchwork
2026-11-11  7:06 ` ✓ 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=avTD6oXFiZcjPmAg@intel.com \
    --to=rodrigo.vivi@intel.com \
    --cc=fei.yang@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=stuart.summers@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.