Advertise each NPM board attribute from a per-field R/W bitmap instead of probing a single sensor. SMU 13.0.6/13.0.12 reports the cap only when NPM metrics and MaxNodePowerLimit are present.
Signed-off-by: Lijo Lazar <[email protected]> Assisted-by: Cursor Grok 4.6 --- .../gpu/drm/amd/include/kgd_pp_interface.h | 16 +++++++ drivers/gpu/drm/amd/pm/amdgpu_dpm.c | 23 +++++++++ drivers/gpu/drm/amd/pm/amdgpu_pm.c | 47 +++++++++++++------ drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 1 + drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 11 +++++ drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 7 +++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 19 ++++++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h | 1 + 9 files changed, 111 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 606d48115301..5e8476c4b808 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -174,6 +174,21 @@ enum amd_pp_sensors { AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, }; +/* + * NPM sysfs capability bitmap: two bits per field, R then W. + * 00 = unsupported, 01 = read-only, 1x = writable (or RW). + */ +enum amdgpu_npm_cap_field { + AMDGPU_NPM_CAP_CUR_NODE_POWER_LIMIT, + AMDGPU_NPM_CAP_NODE_POWER, + AMDGPU_NPM_CAP_GLOBAL_PPT_RESID, + AMDGPU_NPM_CAP_MAX_NODE_POWER_LIMIT, + AMDGPU_NPM_CAP_NPM_STATUS, +}; + +#define AMDGPU_NPM_CAP_R(field) BIT_ULL((field) * 2) +#define AMDGPU_NPM_CAP_W(field) BIT_ULL((field) * 2 + 1) + enum amd_pp_task { AMD_PP_TASK_DISPLAY_CONFIG_CHANGE, AMD_PP_TASK_ENABLE_USER_STATE, @@ -513,6 +528,7 @@ struct amd_pm_funcs { ssize_t (*get_gpu_metrics)(void *handle, void **table); ssize_t (*get_temp_metrics)(void *handle, enum smu_temp_metric_type type, void *table); bool (*temp_metrics_is_supported)(void *handle, enum smu_temp_metric_type type); + u64 (*get_npm_cap)(void *handle); ssize_t (*get_xcp_metrics)(void *handle, int xcp_id, void *table); ssize_t (*get_pm_metrics)(void *handle, void *pmmetrics, size_t size); int (*set_watermarks_for_clock_ranges)(void *handle, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index c70fd6691461..df5bbdab1ea3 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -2101,6 +2101,29 @@ bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, return support_temp_metrics; } +/** + * amdgpu_dpm_get_npm_cap - Return NPM sysfs capability bitmap + * @adev: Pointer to the device. + * + * Two bits per field (R then W). Both 0 means the field is unsupported. + * + * Return: Capability bitmap, or 0 if NPM is not supported. + */ +u64 amdgpu_dpm_get_npm_cap(struct amdgpu_device *adev) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + u64 cap = 0; + + if (!pp_funcs || !pp_funcs->get_npm_cap) + return 0; + + mutex_lock(&adev->pm.mutex); + cap = pp_funcs->get_npm_cap(adev->powerplay.pp_handle); + mutex_unlock(&adev->pm.mutex); + + return cap; +} + /** * amdgpu_dpm_get_xcp_metrics - Retrieve metrics for a specific compute * partition diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index c0e677328af5..6f8252376127 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -4726,6 +4726,37 @@ static int amdgpu_od_set_init(struct amdgpu_device *adev) return ret; } +static void amdgpu_pm_npm_sysfs_init(struct amdgpu_device *adev) +{ + static const struct { + struct device_attribute *attr; + unsigned int field; + } files[] = { + { &dev_attr_cur_node_power_limit, AMDGPU_NPM_CAP_CUR_NODE_POWER_LIMIT }, + { &dev_attr_node_power, AMDGPU_NPM_CAP_NODE_POWER }, + { &dev_attr_global_ppt_resid, AMDGPU_NPM_CAP_GLOBAL_PPT_RESID }, + { &dev_attr_max_node_power_limit, AMDGPU_NPM_CAP_MAX_NODE_POWER_LIMIT }, + { &dev_attr_npm_status, AMDGPU_NPM_CAP_NPM_STATUS }, + }; + u64 cap = amdgpu_dpm_get_npm_cap(adev); + int i; + + if (!cap) + return; + + for (i = 0; i < ARRAY_SIZE(files); i++) { + unsigned int bits = (cap >> (files[i].field * 2)) & 0x3; + struct device_attribute *attr = files[i].attr; + + if (!bits) + continue; + + attr->attr.mode = ((bits & BIT(1)) && attr->store) ? 0644 : 0444; + sysfs_add_file_to_group(&adev->dev->kobj, &attr->attr, + amdgpu_board_attr_group.name); + } +} + int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) { enum amdgpu_sriov_vf_mode mode; @@ -4797,21 +4828,7 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) &amdgpu_board_attr_group); if (ret) goto err_out1; - if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MAXNODEPOWERLIMIT, - (void *)&tmp) != -EOPNOTSUPP) { - sysfs_add_file_to_group(&adev->dev->kobj, - &dev_attr_cur_node_power_limit.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_node_power.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_global_ppt_resid.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, - &dev_attr_max_node_power_limit.attr, - amdgpu_board_attr_group.name); - sysfs_add_file_to_group(&adev->dev->kobj, &dev_attr_npm_status.attr, - amdgpu_board_attr_group.name); - } + amdgpu_pm_npm_sysfs_init(adev); if (amdgpu_pm_get_sensor_generic(adev, AMDGPU_PP_SENSOR_UBB_POWER_LIMIT, (void *)&tmp) != -EOPNOTSUPP) { sysfs_add_file_to_group(&adev->dev->kobj, diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 8e8a052e1d53..ed1e7385243d 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -614,5 +614,6 @@ int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask); bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev); bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev, enum smu_temp_metric_type type); +u64 amdgpu_dpm_get_npm_cap(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 4290a4872f3b..0a6daff8766f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -4002,6 +4002,16 @@ static bool smu_temp_metrics_is_supported(void *handle, enum smu_temp_metric_typ return ret; } +static u64 smu_get_npm_cap(void *handle) +{ + struct smu_context *smu = handle; + + if (!smu->pm_enabled || !smu->ppt_funcs || !smu->ppt_funcs->get_npm_cap) + return 0; + + return smu->ppt_funcs->get_npm_cap(smu); +} + static ssize_t smu_sys_get_xcp_metrics(void *handle, int xcp_id, void *table) { struct smu_context *smu = handle; @@ -4076,6 +4086,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .get_xcp_metrics = smu_sys_get_xcp_metrics, .get_temp_metrics = smu_sys_get_temp_metrics, .temp_metrics_is_supported = smu_temp_metrics_is_supported, + .get_npm_cap = smu_get_npm_cap, }; int smu_wait_for_event(struct smu_context *smu, enum smu_event_type event, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index ab43a5cd0dcd..76625cac74cb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1620,6 +1620,13 @@ struct pptable_funcs { */ ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id, void *table); + /** + * @get_npm_cap: Return NPM sysfs capability bitmap. + * + * Two bits per field (R then W). Both 0 means the field is + * unsupported. + */ + u64 (*get_npm_cap)(struct smu_context *smu); /** * @ras_send_msg: Send a message with a parameter from Ras * &msg: Type of message. diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index d8ddad531d26..0ca5973391e8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -695,6 +695,25 @@ int smu_v13_0_12_get_npm_data(struct smu_context *smu, return ret; } +u64 smu_v13_0_12_get_npm_cap(struct smu_context *smu) +{ + struct PPTable_t *pptable = + (struct PPTable_t *)smu->smu_table.driver_pptable; + u64 cap = 0; + + if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(NPM_METRICS)) || + !pptable->MaxNodePowerLimit) + return 0; + + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_CUR_NODE_POWER_LIMIT); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_NODE_POWER); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_GLOBAL_PPT_RESID); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_MAX_NODE_POWER_LIMIT); + cap |= AMDGPU_NPM_CAP_R(AMDGPU_NPM_CAP_NPM_STATUS); + + return cap; +} + static ssize_t smu_v13_0_12_get_temp_metrics(struct smu_context *smu, enum smu_temp_metric_type type, void *table) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index ee380488d212..83a5a4614a4b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -3312,6 +3312,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .get_gpu_metrics = smu_v13_0_6_get_gpu_metrics, .get_pm_metrics = smu_v13_0_6_get_pm_metrics, .get_xcp_metrics = smu_v13_0_6_get_xcp_metrics, + .get_npm_cap = smu_v13_0_12_get_npm_cap, .get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range, .mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported, .mode1_reset = smu_v13_0_6_mode1_reset, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h index 6554780afff7..1b6926625cc3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h @@ -111,6 +111,7 @@ void smu_v13_0_12_tables_fini(struct smu_context *smu); int smu_v13_0_12_get_npm_data(struct smu_context *smu, enum amd_pp_sensors sensor, uint32_t *value); +u64 smu_v13_0_12_get_npm_cap(struct smu_context *smu); int smu_v13_0_12_get_system_power(struct smu_context *smu, enum amd_pp_sensors sensor, uint32_t *value); -- 2.49.0
