From: Perry Yuan Date: Sun, 8 Feb 2026 16:42:06 +0000 (+0800) Subject: drm/amdgpu: add sysfs for Peak Tops Limiter (PTL) X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=d51a0439358d4eacd8beb39df619998d8340d232;p=thirdparty%2Fkernel%2Flinux.git drm/amdgpu: add sysfs for Peak Tops Limiter (PTL) 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 Reviewed-by: Yifan Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d91bf647757fa..34f933350ccf3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3647,6 +3647,7 @@ static int amdgpu_device_sys_interface_init(struct amdgpu_device *adev) amdgpu_reg_state_sysfs_init(adev); amdgpu_xcp_sysfs_init(adev); amdgpu_uma_sysfs_init(adev); + amdgpu_ptl_sysfs_init(adev); return r; } @@ -3663,6 +3664,7 @@ static void amdgpu_device_sys_interface_fini(struct amdgpu_device *adev) amdgpu_reg_state_sysfs_fini(adev); amdgpu_xcp_sysfs_fini(adev); amdgpu_uma_sysfs_fini(adev); + amdgpu_ptl_sysfs_fini(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 0734ddaf63882..82c96f578a82d 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) { @@ -1312,6 +1321,166 @@ int amdgpu_ptl_perf_monitor_ctrl(struct amdgpu_device *adev, u32 req_code, return psp_ptl_invoke(psp, req_code, ptl_state, &ptl_fmt1, &ptl_fmt2); } +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) { + const char *fmt = amdgpu_ptl_fmt_str[i]; + + len += sysfs_emit_at(buf, len, "%s%s", + fmt ? fmt : "UNKNOWN", + (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 amdgpu_ptl *ptl = &adev->psp.ptl; + uint32_t ptl_state, fmt1, fmt2; + int ret; + bool enable; + + mutex_lock(&ptl->mutex); + if (sysfs_streq(buf, "enabled") || sysfs_streq(buf, "1")) { + enable = true; + } else if (sysfs_streq(buf, "disabled") || sysfs_streq(buf, "0")) { + enable = false; + } else { + mutex_unlock(&ptl->mutex); + return -EINVAL; + } + + fmt1 = ptl->fmt1; + fmt2 = ptl->fmt2; + ptl_state = enable ? 1 : 0; + + ret = amdgpu_ptl_perf_monitor_ctrl(adev, PSP_PTL_PERF_MON_SET, &ptl_state, &fmt1, &fmt2); + if (ret) { + dev_err(adev->dev, "Failed to set PTL err = %d\n", ret); + mutex_unlock(&ptl->mutex); + return ret; + } + + mutex_unlock(&ptl->mutex); + 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 amdgpu_ptl *ptl = &adev->psp.ptl; + + return sysfs_emit(buf, "%s\n", 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); + char fmt1_str[8], fmt2_str[8]; + enum amdgpu_ptl_fmt fmt1_enum, fmt2_enum; + struct amdgpu_ptl *ptl = &adev->psp.ptl; + uint32_t ptl_state, fmt1, fmt2; + int ret; + + /* Only allow format update when PTL is enabled */ + if (!ptl->enabled) + return -EPERM; + + mutex_lock(&ptl->mutex); + /* Parse input, expecting "FMT1,FMT2" */ + if (sscanf(buf, "%7[^,],%7s", fmt1_str, fmt2_str) != 2) { + mutex_unlock(&ptl->mutex); + 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) { + mutex_unlock(&ptl->mutex); + return -EINVAL; + } + + ptl_state = ptl->enabled; + fmt1 = fmt1_enum; + fmt2 = fmt2_enum; + ret = amdgpu_ptl_perf_monitor_ctrl(adev, PSP_PTL_PERF_MON_SET, &ptl_state, &fmt1, &fmt2); + if (ret) { + dev_err(adev->dev, "Failed to update PTL err = %d\n", ret); + mutex_unlock(&ptl->mutex); + return ret; + } + mutex_unlock(&ptl->mutex); + + 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 amdgpu_ptl_sysfs_init(struct amdgpu_device *adev) +{ + if (!adev->psp.ptl.hw_supported) + return 0; + + return sysfs_create_group(&adev->dev->kobj, &amdgpu_ptl_attr_group); +} + +void amdgpu_ptl_sysfs_fini(struct amdgpu_device *adev) +{ + if (!adev->psp.ptl.hw_supported) + return; + + sysfs_remove_group(&adev->dev->kobj, &amdgpu_ptl_attr_group); +} + int psp_spatial_partition(struct psp_context *psp, int mode) { struct psp_gfx_cmd_resp *cmd; @@ -4318,6 +4487,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/include/amdgpu_ptl.h b/drivers/gpu/drm/amd/include/amdgpu_ptl.h index 17e803f4caf83..ffed443a14ae6 100644 --- a/drivers/gpu/drm/amd/include/amdgpu_ptl.h +++ b/drivers/gpu/drm/amd/include/amdgpu_ptl.h @@ -47,4 +47,8 @@ int amdgpu_ptl_perf_monitor_ctrl(struct amdgpu_device *adev, u32 req_code, enum amdgpu_ptl_fmt *fmt1, enum amdgpu_ptl_fmt *fmt2); +int amdgpu_ptl_sysfs_init(struct amdgpu_device *adev); +void amdgpu_ptl_sysfs_fini(struct amdgpu_device *adev); + +extern const struct attribute_group amdgpu_ptl_attr_group; #endif /* __AMDGPU_PTL_H__ */