[PATCH v2] drm/xe: Expose fan control and voltage regulator information
Rodrigo Vivi
rodrigo.vivi at intel.com
Tue Jul 8 19:10:38 UTC 2025
On Fri, Jul 04, 2025 at 04:53:05PM +0530, Raag Jadav wrote:
> Expose sysfs attributes for late binding features which provide information
> about their support, provisioning and bound version to the user.
>
> v2: s/late_bind_fan_info/lb_fan_control_info (Badal)
> s/late_bind_vr_info/lb_voltage_regulator_info (Badal)
> s/LATE_BINDING/PCODE_LATE_BINDING (Badal)
> Add VERSION_MASK macros (Badal)
>
> Signed-off-by: Raag Jadav <raag.jadav at intel.com>
> ---
> drivers/gpu/drm/xe/xe_device_sysfs.c | 121 ++++++++++++++++++++++++++-
> drivers/gpu/drm/xe/xe_pcode_api.h | 15 ++++
> 2 files changed, 135 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_device_sysfs.c b/drivers/gpu/drm/xe/xe_device_sysfs.c
> index b9440f8c781e..8a1bb2b7c951 100644
> --- a/drivers/gpu/drm/xe/xe_device_sysfs.c
> +++ b/drivers/gpu/drm/xe/xe_device_sysfs.c
> @@ -24,6 +24,15 @@
> *
> * vram_d3cold_threshold - Report/change vram used threshold(in MB) below
> * which vram save/restore is permissible during runtime D3cold entry/exit.
> + *
> + * lb_fan_control_info - Fan control information of the device in comma
> + * separated format as ``<supported>,<provisioned>,<version>`` with optional
> + * ``<version>`` field which is available only if provisioned by late binding.
> + *
> + * lb_voltage_regulator_info - Voltage regulator information of the device in
> + * comma separated format as ``<supported>,<provisioned>,<version>`` with
> + * optional ``<version>`` field which is available only if provisioned by late
Ouch. I have to apologize here. I had overseen this patch, but only with the
version in mind. Only now, while I was going to merge this patch that I noticed
it has fancy format against the written rules:
https://docs.kernel.org/6.15/filesystems/sysfs.html
"Mixing types, expressing multiple lines of data, and doing fancy formatting
of data is heavily frowned upon. Doing these things may get you publicly
humiliated and your code rewritten without notice."
For simplicity we should only do lb_fan_control_version and expose that only
if supported and provisioned.
> + * binding.
> */
>
> static ssize_t
> @@ -65,6 +74,110 @@ vram_d3cold_threshold_store(struct device *dev, struct device_attribute *attr,
>
> static DEVICE_ATTR_RW(vram_d3cold_threshold);
>
> +static ssize_t
> +lb_fan_control_info_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct xe_device *xe = pdev_to_xe_device(to_pci_dev(dev));
> + struct xe_tile *root = xe_device_get_root_tile(xe);
> + u32 cap, ver_low = FAN_TABLE, ver_high = FAN_TABLE;
> + bool supported, provisioned;
> + int ret, len = 0;
> +
> + xe_pm_runtime_get(xe);
> +
> + ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_CAPABILITY_STATUS, 0),
> + &cap, NULL);
> + if (ret)
> + goto out;
> +
> + supported = REG_FIELD_GET(V1_FAN_SUPPORTED, cap);
> + provisioned = REG_FIELD_GET(V1_FAN_PROVISIONED, cap);
> +
> + if (provisioned) {
> + ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_LOW, 0),
> + &ver_low, NULL);
> + if (ret)
> + goto out;
> +
> + ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_HIGH, 0),
> + &ver_high, NULL);
> + if (ret)
> + goto out;
> + }
> +
> + len += sysfs_emit_at(buf, len, "%u", supported);
> + len += sysfs_emit_at(buf, len, ",%u", provisioned);
> +
> + if (provisioned)
> + len += sysfs_emit_at(buf, len, ",%u.%u.%u.%u",
> + REG_FIELD_GET(MAJOR_VERSION_MASK, ver_low),
> + REG_FIELD_GET(MINOR_VERSION_MASK, ver_low),
> + REG_FIELD_GET(HOTFIX_VERSION_MASK, ver_high),
> + REG_FIELD_GET(BUILD_VERSION_MASK, ver_high));
> +
> + len += sysfs_emit_at(buf, len, "\n");
> +out:
> + xe_pm_runtime_put(xe);
> +
> + return ret ?: len;
> +}
> +static DEVICE_ATTR_ADMIN_RO(lb_fan_control_info);
> +
> +static ssize_t
> +lb_voltage_regulator_info_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct xe_device *xe = pdev_to_xe_device(to_pci_dev(dev));
> + struct xe_tile *root = xe_device_get_root_tile(xe);
> + u32 cap, ver_low = VR_CONFIG, ver_high = VR_CONFIG;
> + bool supported, provisioned;
> + int ret, len = 0;
> +
> + xe_pm_runtime_get(xe);
> +
> + ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_CAPABILITY_STATUS, 0),
> + &cap, NULL);
> + if (ret)
> + goto out;
> +
> + supported = REG_FIELD_GET(VR_PARAMS_SUPPORTED, cap);
> + provisioned = REG_FIELD_GET(VR_PARAMS_PROVISIONED, cap);
> +
> + if (provisioned) {
> + ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_LOW, 0),
> + &ver_low, NULL);
> + if (ret)
> + goto out;
> +
> + ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_HIGH, 0),
> + &ver_high, NULL);
> + if (ret)
> + goto out;
> + }
> +
> + len += sysfs_emit_at(buf, len, "%u", supported);
> + len += sysfs_emit_at(buf, len, ",%u", provisioned);
> +
> + if (provisioned)
> + len += sysfs_emit_at(buf, len, ",%u.%u.%u.%u",
> + REG_FIELD_GET(MAJOR_VERSION_MASK, ver_low),
> + REG_FIELD_GET(MINOR_VERSION_MASK, ver_low),
> + REG_FIELD_GET(HOTFIX_VERSION_MASK, ver_high),
> + REG_FIELD_GET(BUILD_VERSION_MASK, ver_high));
> +
> + len += sysfs_emit_at(buf, len, "\n");
> +out:
> + xe_pm_runtime_put(xe);
> +
> + return ret ?: len;
> +}
> +static DEVICE_ATTR_ADMIN_RO(lb_voltage_regulator_info);
> +
> +static const struct attribute *late_bind_attrs[] = {
> + &dev_attr_lb_fan_control_info.attr,
> + &dev_attr_lb_voltage_regulator_info.attr,
> + NULL
> +};
> +
> /**
> * DOC: PCIe Gen5 Limitations
> *
> @@ -151,8 +264,10 @@ static void xe_device_sysfs_fini(void *arg)
> if (xe->d3cold.capable)
> sysfs_remove_file(&xe->drm.dev->kobj, &dev_attr_vram_d3cold_threshold.attr);
>
> - if (xe->info.platform == XE_BATTLEMAGE)
> + if (xe->info.platform == XE_BATTLEMAGE) {
> sysfs_remove_files(&xe->drm.dev->kobj, auto_link_downgrade_attrs);
> + sysfs_remove_files(&xe->drm.dev->kobj, late_bind_attrs);
> + }
> }
>
> int xe_device_sysfs_init(struct xe_device *xe)
> @@ -170,6 +285,10 @@ int xe_device_sysfs_init(struct xe_device *xe)
> ret = sysfs_create_files(&dev->kobj, auto_link_downgrade_attrs);
> if (ret)
> return ret;
> +
> + ret = sysfs_create_files(&dev->kobj, late_bind_attrs);
> + if (ret)
> + return ret;
> }
>
> return devm_add_action_or_reset(dev, xe_device_sysfs_fini, xe);
> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
> index 0befdea77db1..92bfcba51e19 100644
> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
> @@ -50,6 +50,21 @@
> #define READ_PL_FROM_FW 0x1
> #define READ_PL_FROM_PCODE 0x0
>
> +#define PCODE_LATE_BINDING 0x5C
> +#define GET_CAPABILITY_STATUS 0x0
> +#define V1_FAN_SUPPORTED REG_BIT(0)
> +#define VR_PARAMS_SUPPORTED REG_BIT(3)
> +#define V1_FAN_PROVISIONED REG_BIT(16)
> +#define VR_PARAMS_PROVISIONED REG_BIT(19)
> +#define GET_VERSION_LOW 0x1
> +#define GET_VERSION_HIGH 0x2
> +#define MAJOR_VERSION_MASK REG_GENMASK(31, 16)
> +#define MINOR_VERSION_MASK REG_GENMASK(15, 0)
> +#define HOTFIX_VERSION_MASK REG_GENMASK(31, 16)
> +#define BUILD_VERSION_MASK REG_GENMASK(15, 0)
> +#define FAN_TABLE 1
> +#define VR_CONFIG 2
> +
> #define PCODE_FREQUENCY_CONFIG 0x6e
> /* Frequency Config Sub Commands (param1) */
> #define PCODE_MBOX_FC_SC_READ_FUSED_P0 0x0
> --
> 2.34.1
>
More information about the Intel-xe
mailing list