[V2 3/8] drm/amd/pm: add fan mode OD setting support for SMU13
Alex Deucher
alexdeucher at gmail.com
Wed Aug 23 13:29:09 UTC 2023
On Wed, Aug 23, 2023 at 2:45 AM Evan Quan <evan.quan at amd.com> wrote:
>
> Add SMU13 fan mode OD setting support.
>
> Signed-off-by: Evan Quan <evan.quan at amd.com>
> --
> v1->v2:
> - add missing kerneldoc for the new interface(Alex)
> ---
> Documentation/gpu/amdgpu/thermal.rst | 6 +
> .../gpu/drm/amd/include/kgd_pp_interface.h | 4 +-
> drivers/gpu/drm/amd/pm/amdgpu_pm.c | 200 +++++++++++++++++-
> drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h | 4 +
> drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 2 +
> drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 1 +
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 35 ++-
> .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 35 ++-
> 8 files changed, 279 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/gpu/amdgpu/thermal.rst b/Documentation/gpu/amdgpu/thermal.rst
> index 5e27e4eb3959..8757ec7f0136 100644
> --- a/Documentation/gpu/amdgpu/thermal.rst
> +++ b/Documentation/gpu/amdgpu/thermal.rst
> @@ -64,6 +64,12 @@ gpu_metrics
> .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
> :doc: gpu_metrics
>
> +fan_mode
> +--------
> +
> +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
> + :doc: fan_mode
> +
> GFXOFF
> ======
>
> diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> index 84c5224d994c..020c9ce1f735 100644
> --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> @@ -113,6 +113,7 @@ enum pp_clock_type {
> OD_RANGE,
> OD_VDDGFX_OFFSET,
> OD_CCLK,
> + OD_FAN_MODE,
> };
>
> enum amd_pp_sensors {
> @@ -186,7 +187,8 @@ enum PP_OD_DPM_TABLE_COMMAND {
> PP_OD_EDIT_VDDC_CURVE,
> PP_OD_RESTORE_DEFAULT_TABLE,
> PP_OD_COMMIT_DPM_TABLE,
> - PP_OD_EDIT_VDDGFX_OFFSET
> + PP_OD_EDIT_VDDGFX_OFFSET,
> + PP_OD_EDIT_FAN_MODE,
> };
>
> struct pp_states_info {
> diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> index beb3303fc832..d53d60903fe9 100644
> --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
> @@ -3383,7 +3383,205 @@ static const struct attribute_group *hwmon_groups[] = {
> NULL
> };
>
> -static struct od_feature_set amdgpu_od_set;
> +static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev,
> + enum pp_clock_type od_type,
> + char *buf)
> +{
> + int size = 0;
> + int ret;
> +
> + if (amdgpu_in_reset(adev))
> + return -EPERM;
> + if (adev->in_suspend && !adev->in_runpm)
> + return -EPERM;
> +
> + ret = pm_runtime_get_sync(adev->dev);
> + if (ret < 0) {
> + pm_runtime_put_autosuspend(adev->dev);
> + return ret;
> + }
> +
> + size = amdgpu_dpm_print_clock_levels(adev, od_type, buf);
> + if (size == 0)
> + size = sysfs_emit(buf, "\n");
> +
> + pm_runtime_mark_last_busy(adev->dev);
> + pm_runtime_put_autosuspend(adev->dev);
> +
> + return size;
> +}
> +
> +static int parse_input_od_command_lines(const char *buf,
> + size_t count,
> + u32 *type,
> + long *params,
> + uint32_t *num_of_params)
> +{
> + const char delimiter[3] = {' ', '\n', '\0'};
> + uint32_t parameter_size = 0;
> + char buf_cpy[128] = {0};
> + char *tmp_str, *sub_str;
> + int ret;
> +
> + if (count > sizeof(buf_cpy) - 1)
> + return -EINVAL;
> +
> + memcpy(buf_cpy, buf, count);
> + tmp_str = buf_cpy;
> +
> + /* skip heading spaces */
> + while (isspace(*tmp_str))
> + tmp_str++;
> +
> + switch (*tmp_str) {
> + case 'c':
> + *type = PP_OD_COMMIT_DPM_TABLE;
> + return 0;
> + default:
> + break;
> + }
> +
> + while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
> + if (strlen(sub_str) == 0)
> + continue;
> +
> + ret = kstrtol(sub_str, 0, ¶ms[parameter_size]);
> + if (ret)
> + return -EINVAL;
> + parameter_size++;
> +
> + while (isspace(*tmp_str))
> + tmp_str++;
> + }
> +
> + *num_of_params = parameter_size;
> +
> + return 0;
> +}
> +
> +static int
> +amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev,
> + enum PP_OD_DPM_TABLE_COMMAND cmd_type,
> + const char *in_buf,
> + size_t count)
> +{
> + uint32_t parameter_size = 0;
> + long parameter[64];
> + int ret;
> +
> + if (amdgpu_in_reset(adev))
> + return -EPERM;
> + if (adev->in_suspend && !adev->in_runpm)
> + return -EPERM;
> +
> + ret = parse_input_od_command_lines(in_buf,
> + count,
> + &cmd_type,
> + parameter,
> + ¶meter_size);
> + if (ret)
> + return ret;
> +
> + ret = pm_runtime_get_sync(adev->dev);
> + if (ret < 0)
> + goto err_out0;
> +
> + ret = amdgpu_dpm_odn_edit_dpm_table(adev,
> + cmd_type,
> + parameter,
> + parameter_size);
> + if (ret)
> + goto err_out1;
> +
> + if (cmd_type == PP_OD_COMMIT_DPM_TABLE) {
> + ret = amdgpu_dpm_dispatch_task(adev,
> + AMD_PP_TASK_READJUST_POWER_STATE,
> + NULL);
> + if (ret)
> + goto err_out1;
> + }
> +
> + pm_runtime_mark_last_busy(adev->dev);
> + pm_runtime_put_autosuspend(adev->dev);
> +
> + return count;
> +
> +err_out1:
> + pm_runtime_mark_last_busy(adev->dev);
> +err_out0:
> + pm_runtime_put_autosuspend(adev->dev);
> +
> + return ret;
> +}
> +
> +/**
> + * DOC: fan_mode
> + *
> + * The amdgpu driver provides a sysfs API for checking and adjusting the fan
> + * control mode.
> + *
> + * Reading back the file shows you current fan control mode (e.g. '0' for auto
> + * mode and '1' for manual mode) and permitted settings if changable.
typo: changeable
Also what does manual vs auto mean in this case? Is the idea that you
need to switch to manual mode before you make any other adjustments
(fan curve or acoustic) or is this some independent setting?
Alex
> + *
> + * Writing an integer to the file, sets the fan control mode correspondingly.
> + *
> + * When you have finished the editing, write "c" (commit) to the file to commit
> + * your changes.
> + */
> +static ssize_t fan_mode_show(struct kobject *kobj,
> + struct kobj_attribute *attr,
> + char *buf)
> +{
> + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj);
> + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv;
> +
> + return (ssize_t)amdgpu_retrieve_od_settings(adev, OD_FAN_MODE, buf);
> +}
> +
> +static ssize_t fan_mode_store(struct kobject *kobj,
> + struct kobj_attribute *attr,
> + const char *buf,
> + size_t count)
> +{
> + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj);
> + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv;
> +
> + return (ssize_t)amdgpu_distribute_custom_od_settings(adev,
> + PP_OD_EDIT_FAN_MODE,
> + buf,
> + count);
> +}
> +
> +static umode_t fan_mode_visible(struct amdgpu_device *adev)
> +{
> + umode_t umode = 0000;
> +
> + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_MODE_RETRIEVE)
> + umode |= S_IRUSR | S_IRGRP | S_IROTH;
> +
> + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_MODE_SET)
> + umode |= S_IWUSR;
> +
> + return umode;
> +}
> +
> +static struct od_feature_set amdgpu_od_set = {
> + .containers = {
> + [0] = {
> + .name = "fan_ctrl",
> + .sub_feature = {
> + [0] = {
> + .name = "fan_mode",
> + .ops = {
> + .is_visible = fan_mode_visible,
> + .show = fan_mode_show,
> + .store = fan_mode_store,
> + },
> + },
> + },
> + },
> + },
> +};
>
> static void od_kobj_release(struct kobject *kobj)
> {
> diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> index 4cab6a2efb63..b54f84e2408a 100644
> --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
> @@ -314,6 +314,9 @@ struct config_table_setting
> uint16_t fclk_average_tau;
> };
>
> +#define OD_OPS_SUPPORT_FAN_MODE_RETRIEVE BIT(0)
> +#define OD_OPS_SUPPORT_FAN_MODE_SET BIT(1)
> +
> struct amdgpu_pm {
> struct mutex mutex;
> u32 current_sclk;
> @@ -368,6 +371,7 @@ struct amdgpu_pm {
> enum amdgpu_runpm_mode rpm_mode;
>
> struct list_head od_kobj_list;
> + uint32_t od_feature_mask;
> };
>
> int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor,
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index f005a90c35af..01ccfd219d6b 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -2481,6 +2481,8 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type)
> clk_type = SMU_OD_VDDGFX_OFFSET; break;
> case OD_CCLK:
> clk_type = SMU_OD_CCLK; break;
> + case OD_FAN_MODE:
> + clk_type = SMU_OD_FAN_MODE; break;
> default:
> clk_type = SMU_CLK_COUNT; break;
> }
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> index e57265cf637c..498000850212 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> @@ -280,6 +280,7 @@ enum smu_clk_type {
> SMU_OD_VDDC_CURVE,
> SMU_OD_RANGE,
> SMU_OD_VDDGFX_OFFSET,
> + SMU_OD_FAN_MODE,
> SMU_CLK_COUNT,
> };
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> index 1041ba22f8f8..45b42e43f9a3 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
> @@ -101,6 +101,7 @@
> #define PP_OD_FEATURE_UCLK_FMIN 2
> #define PP_OD_FEATURE_UCLK_FMAX 3
> #define PP_OD_FEATURE_GFX_VF_CURVE 4
> +#define PP_OD_FEATURE_FAN_MODE 5
>
> #define LINK_SPEED_MAX 3
>
> @@ -1110,6 +1111,10 @@ static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
> od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary;
> od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary;
> break;
> + case PP_OD_FEATURE_FAN_MODE:
> + od_min_setting = overdrive_lowerlimits->FanMode;
> + od_max_setting = overdrive_upperlimits->FanMode;
> + break;
> default:
> od_min_setting = od_max_setting = INT_MAX;
> break;
> @@ -1329,6 +1334,16 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
> od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]);
> break;
>
> + case SMU_OD_FAN_MODE:
> + if (!smu_v13_0_0_is_od_feature_supported(smu,
> + PP_OD_FEATURE_FAN_CURVE_BIT))
> + break;
> +
> + size += sysfs_emit_at(buf, size, "OD_FAN_MODE:\n");
> + size += sysfs_emit_at(buf, size, "%d\n",
> + (int)od_table->OverDriveTable.FanMode);
> + break;
> +
> case SMU_OD_RANGE:
> if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) &&
> !smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) &&
> @@ -1789,6 +1804,15 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
> return sizeof(struct gpu_metrics_v1_3);
> }
>
> +static void smu_v13_0_0_set_supported_od_feature_mask(struct smu_context *smu)
> +{
> + struct amdgpu_device *adev = smu->adev;
> +
> + if (smu_v13_0_0_is_od_feature_supported(smu,
> + PP_OD_FEATURE_FAN_CURVE_BIT))
> + adev->pm.od_feature_mask |= OD_OPS_SUPPORT_FAN_MODE_RETRIEVE;
> +}
> +
> static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
> {
> OverDriveTableExternal_t *od_table =
> @@ -1838,8 +1862,12 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
> for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++)
> user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] =
> user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i];
> + user_od_table->OverDriveTable.FanMode =
> + user_od_table_bak.OverDriveTable.FanMode;
> }
>
> + smu_v13_0_0_set_supported_od_feature_mask(smu);
> +
> return 0;
> }
>
> @@ -1850,9 +1878,10 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu)
> OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
> int res;
>
> - user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT |
> - 1U << PP_OD_FEATURE_UCLK_BIT |
> - 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT;
> + user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
> + BIT(PP_OD_FEATURE_UCLK_BIT) |
> + BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
> + BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
> res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table);
> user_od_table->OverDriveTable.FeatureCtrlMask = 0;
> if (res == 0)
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> index 328765f89c94..28c2e4b0e55d 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
> @@ -77,6 +77,7 @@
> #define PP_OD_FEATURE_UCLK_FMIN 2
> #define PP_OD_FEATURE_UCLK_FMAX 3
> #define PP_OD_FEATURE_GFX_VF_CURVE 4
> +#define PP_OD_FEATURE_FAN_MODE 5
>
> #define LINK_SPEED_MAX 3
>
> @@ -1096,6 +1097,10 @@ static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
> od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary;
> od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary;
> break;
> + case PP_OD_FEATURE_FAN_MODE:
> + od_min_setting = overdrive_lowerlimits->FanMode;
> + od_max_setting = overdrive_upperlimits->FanMode;
> + break;
> default:
> od_min_setting = od_max_setting = INT_MAX;
> break;
> @@ -1315,6 +1320,16 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,
> od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]);
> break;
>
> + case SMU_OD_FAN_MODE:
> + if (!smu_v13_0_7_is_od_feature_supported(smu,
> + PP_OD_FEATURE_FAN_CURVE_BIT))
> + break;
> +
> + size += sysfs_emit_at(buf, size, "OD_FAN_MODE:\n");
> + size += sysfs_emit_at(buf, size, "%d\n",
> + (int)od_table->OverDriveTable.FanMode);
> + break;
> +
> case SMU_OD_RANGE:
> if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) &&
> !smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) &&
> @@ -1770,6 +1785,15 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
> return sizeof(struct gpu_metrics_v1_3);
> }
>
> +static void smu_v13_0_7_set_supported_od_feature_mask(struct smu_context *smu)
> +{
> + struct amdgpu_device *adev = smu->adev;
> +
> + if (smu_v13_0_7_is_od_feature_supported(smu,
> + PP_OD_FEATURE_FAN_CURVE_BIT))
> + adev->pm.od_feature_mask |= OD_OPS_SUPPORT_FAN_MODE_RETRIEVE;
> +}
> +
> static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
> {
> OverDriveTableExternal_t *od_table =
> @@ -1819,8 +1843,12 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
> for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++)
> user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] =
> user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i];
> + user_od_table->OverDriveTable.FanMode =
> + user_od_table_bak.OverDriveTable.FanMode;
> }
>
> + smu_v13_0_7_set_supported_od_feature_mask(smu);
> +
> return 0;
> }
>
> @@ -1831,9 +1859,10 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu)
> OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
> int res;
>
> - user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT |
> - 1U << PP_OD_FEATURE_UCLK_BIT |
> - 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT;
> + user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
> + BIT(PP_OD_FEATURE_UCLK_BIT) |
> + BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
> + BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
> res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table);
> user_od_table->OverDriveTable.FeatureCtrlMask = 0;
> if (res == 0)
> --
> 2.34.1
>
More information about the amd-gfx
mailing list