On Thu, Feb 5, 2026 at 2:02 AM Perry Yuan <[email protected]> wrote:
>
> Add per-GPU sysfs files under /sys/class/drm/cardX/device/ptl to
> control the Peak Tops Limiter (PTL) feature. Exposes ptl_enable
> (enable/disable PTL), ptl_format (set/query preferred formats),
> and ptl_supported_formats (list supported formats)
>
> Example usage
> -------------
> Query PTL status:
> `cat /sys/class/drm/card1/device/ptl/ptl_enable`
>
> Enable PTL:
> `sudo bash -c "echo 1 > /sys/class/drm/card1/device/ptl/ptl_enable"`
>
> Disable PTL:
> `sudo bash -c "echo 0 > /sys/class/drm/card1/device/ptl/ptl_enable"`
>
> Set PTL preferred formats:
> `sudo bash -c "echo I8,F32 > /sys/class/drm/card1/device/ptl/ptl_format"`
>
> Query supported formats:
> `cat /sys/class/drm/card1/device/ptl/ptl_supported_formats`
>
> v3 changes:
> * move N/A to previous format in format show(Alex)
> * fix format check for format store(Alex)
> * drop the ptl declarations into amdgpu_ptl.h(Alex)
>
> v2 changes:
> * add usage commands in commit info (Alex)
> * move amdgpu_ptl_fmt into kgd_kfd_interface.h (Alex)
>
> Signed-off-by: Perry Yuan <[email protected]>
> Reviewed-by: Yifan Zhang <[email protected]>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 168 ++++++++++++++++++++++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 3 +
> 3 files changed, 172 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 95d26f086d54..d88da1beb532 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -3146,6 +3146,7 @@ static const struct attribute_group
> *amdgpu_sysfs_groups[] = {
> &amdgpu_vram_mgr_attr_group,
> &amdgpu_gtt_mgr_attr_group,
> &amdgpu_flash_attr_group,
> + &amdgpu_ptl_attr_group,
> NULL,
> };
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> index 2fbc3f95fedd..9cb30f3e21be 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
> @@ -52,6 +52,15 @@ static int psp_load_smu_fw(struct psp_context *psp);
> static int psp_rap_terminate(struct psp_context *psp);
> static int psp_securedisplay_terminate(struct psp_context *psp);
>
> +static const char * const amdgpu_ptl_fmt_str[] = {
> + [AMDGPU_PTL_FMT_I8] = "I8",
> + [AMDGPU_PTL_FMT_F16] = "F16",
> + [AMDGPU_PTL_FMT_BF16] = "BF16",
> + [AMDGPU_PTL_FMT_F32] = "F32",
> + [AMDGPU_PTL_FMT_F64] = "F64",
> + [AMDGPU_PTL_FMT_INVALID] = "INVALID",
> +};
> +
> static int psp_ring_init(struct psp_context *psp,
> enum psp_ring_type ring_type)
> {
> @@ -1277,6 +1286,140 @@ int psp_performance_monitor_hw(struct psp_context
> *psp, u32 req_code,
> return ret;
> }
>
> +static enum amdgpu_ptl_fmt str_to_ptl_fmt(const char *str)
> +{
> + int i;
> +
> + for (i = 0; i < AMDGPU_PTL_FMT_INVALID; ++i) {
> + if (!strcmp(str, amdgpu_ptl_fmt_str[i]))
> + return (enum amdgpu_ptl_fmt)i;
> + }
> +
> + return AMDGPU_PTL_FMT_INVALID;
> +}
> +
> +static ssize_t ptl_supported_formats_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + ssize_t len = 0;
> +
> + for (int i = 0; i < AMDGPU_PTL_FMT_INVALID; ++i) {
> + len += sysfs_emit_at(buf, len, "%s%s",
> + amdgpu_ptl_fmt_str[i],
> + (i < AMDGPU_PTL_FMT_INVALID - 1) ? "," :
> "\n");
> + }
> +
> + return len;
> +}
> +
> +static ssize_t ptl_enable_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = drm_to_adev(ddev);
> + struct psp_context *psp = &adev->psp;
> + bool enable, cur_enabled;
> + uint32_t ptl_state, fmt1, fmt2;
> + int ret;
> +
> + if (sysfs_streq(buf, "enabled") || sysfs_streq(buf, "1"))
"enable"
> + enable = true;
> + else if (sysfs_streq(buf, "disabled") || sysfs_streq(buf, "0"))
"disable"
Alex
> + enable = false;
> + else
> + return -EINVAL;
> +
> + fmt1 = psp->ptl_fmt1;
> + fmt2 = psp->ptl_fmt2;
> + ptl_state = enable ? 1 : 0;
> +
> + cur_enabled = READ_ONCE(psp->ptl_enabled);
> + if (cur_enabled == enable)
> + return count;
> +
> + ret = psp_performance_monitor_hw(psp, PSP_PTL_PERF_MON_SET,
> &ptl_state, &fmt1, &fmt2);
> + if (ret) {
> + dev_err(adev->dev, "Failed to set PTL err = %d\n", ret);
> + return ret;
> + }
> +
> + return count;
> +}
> +
> +static ssize_t ptl_enable_show(struct device *dev, struct device_attribute
> *attr, char *buf)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = drm_to_adev(ddev);
> + struct psp_context *psp = &adev->psp;
> +
> + return sysfs_emit(buf, "%s\n", psp->ptl_enabled ? "enabled" :
> "disabled");
> +}
> +
> +static ssize_t ptl_format_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = drm_to_adev(ddev);
> + struct psp_context *psp = &adev->psp;
> + char fmt1_str[8], fmt2_str[8];
> + enum amdgpu_ptl_fmt fmt1_enum, fmt2_enum;
> + uint32_t ptl_state, fmt1, fmt2;
> + int ret;
> +
> + /* Only allow format update when PTL is enabled */
> + if (!psp->ptl_enabled)
> + return -EPERM;
> +
> + /* Parse input, expecting "FMT1,FMT2" */
> + if (sscanf(buf, "%7[^,],%7s", fmt1_str, fmt2_str) != 2)
> + return -EINVAL;
> +
> + fmt1_enum = str_to_ptl_fmt(fmt1_str);
> + fmt2_enum = str_to_ptl_fmt(fmt2_str);
> +
> + if (fmt1_enum >= AMDGPU_PTL_FMT_INVALID ||
> + fmt2_enum >= AMDGPU_PTL_FMT_INVALID ||
> + fmt1_enum == fmt2_enum)
> + return -EINVAL;
> +
> + ptl_state = psp->ptl_enabled;
> + fmt1 = fmt1_enum;
> + fmt2 = fmt2_enum;
> + ret = psp_performance_monitor_hw(psp, PSP_PTL_PERF_MON_SET,
> &ptl_state, &fmt1, &fmt2);
> + if (ret) {
> + dev_err(adev->dev, "Failed to update PTL err = %d\n", ret);
> + return ret;
> + }
> +
> + return count;
> +}
> +
> +static ssize_t ptl_format_show(struct device *dev, struct device_attribute
> *attr, char *buf)
> +{
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = drm_to_adev(ddev);
> + struct psp_context *psp = &adev->psp;
> +
> + return sysfs_emit(buf, "%s,%s\n",
> + amdgpu_ptl_fmt_str[psp->ptl_fmt1],
> + amdgpu_ptl_fmt_str[psp->ptl_fmt2]);
> +}
> +
> +static umode_t amdgpu_ptl_is_visible(struct kobject *kobj, struct attribute
> *attr, int idx)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct drm_device *ddev = dev_get_drvdata(dev);
> + struct amdgpu_device *adev = drm_to_adev(ddev);
> +
> + /* Only show PTL sysfs files if PTL hardware is supported */
> + if (!adev->psp.ptl_hw_supported)
> + return 0;
> +
> + return attr->mode;
> +}
> +
> int psp_spatial_partition(struct psp_context *psp, int mode)
> {
> struct psp_gfx_cmd_resp *cmd;
> @@ -4271,6 +4414,31 @@ void psp_copy_fw(struct psp_context *psp, uint8_t
> *start_addr, uint32_t bin_size
> static DEVICE_ATTR(usbc_pd_fw, 0644,
> psp_usbc_pd_fw_sysfs_read,
> psp_usbc_pd_fw_sysfs_write);
> +/**
> + * DOC: PTL sysfs attributes
> + * These sysfs files under /sys/class/drm/cardX/device/ptl allow users to
> enable or disable
> + * the Peak Tops Limiter (PTL), configure preferred PTL data formats, and
> query supported
> + * formats for each GPU.
> + */
> +static DEVICE_ATTR(ptl_enable, 0644,
> + ptl_enable_show, ptl_enable_store);
> +static DEVICE_ATTR(ptl_format, 0644,
> + ptl_format_show, ptl_format_store);
> +static DEVICE_ATTR(ptl_supported_formats, 0444,
> + ptl_supported_formats_show, NULL);
> +
> +static struct attribute *ptl_attrs[] = {
> + &dev_attr_ptl_enable.attr,
> + &dev_attr_ptl_format.attr,
> + &dev_attr_ptl_supported_formats.attr,
> + NULL,
> +};
> +
> +const struct attribute_group amdgpu_ptl_attr_group = {
> + .name = "ptl",
> + .attrs = ptl_attrs,
> + .is_visible = amdgpu_ptl_is_visible,
> +};
>
> int is_psp_fw_valid(struct psp_bin_desc bin)
> {
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> index 47c8becbf710..0a2f8d33a0ad 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
> @@ -63,6 +63,7 @@
> #define MBOX_TOS_RESP_MASK (GFX_CMD_RESPONSE_MASK | GFX_CMD_STATUS_MASK)
>
> extern const struct attribute_group amdgpu_flash_attr_group;
> +extern const struct attribute_group amdgpu_ptl_attr_group;
>
> enum psp_shared_mem_size {
> PSP_ASD_SHARED_MEM_SIZE = 0x0,
> @@ -660,5 +661,7 @@ int amdgpu_psp_get_fw_type(struct amdgpu_firmware_info
> *ucode,
>
> int psp_performance_monitor_hw(struct psp_context *psp, u32 req_code,
> u32 *ptl_state, u32 *fmt1, u32 *fmt2);
> +int amdgpu_ptl_sysfs_init(struct amdgpu_device *adev);
> +void amdgpu_ptl_sysfs_fini(struct amdgpu_device *adev);
>
> #endif
> --
> 2.34.1
>