mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-07-04 00:03:25 -04:00
drm/amdgpu: added a sysfs interface for thermal throttling
added a sysfs interface for thermal throttling, then userspace can get/update thermal limit Signed-off-by: Kun Liu <Kun.Liu2@amd.com> Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
4f101d5710
commit
c3ed0e72c8
6 changed files with 146 additions and 0 deletions
|
@ -331,6 +331,8 @@ struct amd_pm_funcs {
|
|||
int (*get_mclk_od)(void *handle);
|
||||
int (*set_mclk_od)(void *handle, uint32_t value);
|
||||
int (*read_sensor)(void *handle, int idx, void *value, int *size);
|
||||
int (*get_apu_thermal_limit)(void *handle, uint32_t *limit);
|
||||
int (*set_apu_thermal_limit)(void *handle, uint32_t limit);
|
||||
enum amd_dpm_forced_level (*get_performance_level)(void *handle);
|
||||
enum amd_pm_state_type (*get_current_power_state)(void *handle);
|
||||
int (*get_fan_speed_rpm)(void *handle, uint32_t *rpm);
|
||||
|
|
|
@ -456,6 +456,34 @@ int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors senso
|
|||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_get_apu_thermal_limit(struct amdgpu_device *adev, uint32_t *limit)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (pp_funcs && pp_funcs->get_apu_thermal_limit) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
ret = pp_funcs->get_apu_thermal_limit(adev->powerplay.pp_handle, limit);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_dpm_set_apu_thermal_limit(struct amdgpu_device *adev, uint32_t limit)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (pp_funcs && pp_funcs->set_apu_thermal_limit) {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
ret = pp_funcs->set_apu_thermal_limit(adev->powerplay.pp_handle, limit);
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void amdgpu_dpm_compute_clocks(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
|
||||
|
|
|
@ -1685,6 +1685,82 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: apu_thermal_cap
|
||||
*
|
||||
* The amdgpu driver provides a sysfs API for retrieving/updating thermal
|
||||
* limit temperature in millidegrees Celsius
|
||||
*
|
||||
* Reading back the file shows you core limit value
|
||||
*
|
||||
* Writing an integer to the file, sets a new thermal limit. The value
|
||||
* should be between 0 and 100. If the value is less than 0 or greater
|
||||
* than 100, then the write request will be ignored.
|
||||
*/
|
||||
static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret, size;
|
||||
u32 limit;
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
|
||||
ret = pm_runtime_get_sync(ddev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = amdgpu_dpm_get_apu_thermal_limit(adev, &limit);
|
||||
if (!ret)
|
||||
size = sysfs_emit(buf, "%u\n", limit);
|
||||
else
|
||||
size = sysfs_emit(buf, "failed to get thermal limit\n");
|
||||
|
||||
pm_runtime_mark_last_busy(ddev->dev);
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_set_apu_thermal_cap(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int ret;
|
||||
u32 value;
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
|
||||
ret = kstrtou32(buf, 10, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (value < 0 || value > 100) {
|
||||
dev_err(dev, "Invalid argument !\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = pm_runtime_get_sync(ddev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = amdgpu_dpm_set_apu_thermal_limit(adev, value);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to update thermal limit\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(ddev->dev);
|
||||
pm_runtime_put_autosuspend(ddev->dev);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: gpu_metrics
|
||||
*
|
||||
|
@ -1937,6 +2013,7 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = {
|
|||
AMDGPU_DEVICE_ATTR_RW(pp_features, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RO(unique_id, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(thermal_throttling_logging, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RW(apu_thermal_cap, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RO(gpu_metrics, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
|
||||
AMDGPU_DEVICE_ATTR_RO(smartshift_apu_power, ATTR_FLAG_BASIC,
|
||||
.attr_update = ss_power_attr_update),
|
||||
|
|
|
@ -369,6 +369,9 @@ struct amdgpu_pm {
|
|||
int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor,
|
||||
void *data, uint32_t *size);
|
||||
|
||||
int amdgpu_dpm_get_apu_thermal_limit(struct amdgpu_device *adev, uint32_t *limit);
|
||||
int amdgpu_dpm_set_apu_thermal_limit(struct amdgpu_device *adev, uint32_t limit);
|
||||
|
||||
int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev,
|
||||
uint32_t block_type, bool gate);
|
||||
|
||||
|
|
|
@ -2532,6 +2532,28 @@ unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int smu_get_apu_thermal_limit(void *handle, uint32_t *limit)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct smu_context *smu = handle;
|
||||
|
||||
if (smu->ppt_funcs && smu->ppt_funcs->get_apu_thermal_limit)
|
||||
ret = smu->ppt_funcs->get_apu_thermal_limit(smu, limit);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smu_set_apu_thermal_limit(void *handle, uint32_t limit)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct smu_context *smu = handle;
|
||||
|
||||
if (smu->ppt_funcs && smu->ppt_funcs->set_apu_thermal_limit)
|
||||
ret = smu->ppt_funcs->set_apu_thermal_limit(smu, limit);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smu_get_power_profile_mode(void *handle, char *buf)
|
||||
{
|
||||
struct smu_context *smu = handle;
|
||||
|
@ -3033,6 +3055,8 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
|
|||
.emit_clock_levels = smu_emit_ppclk_levels,
|
||||
.force_performance_level = smu_force_performance_level,
|
||||
.read_sensor = smu_read_sensor,
|
||||
.get_apu_thermal_limit = smu_get_apu_thermal_limit,
|
||||
.set_apu_thermal_limit = smu_set_apu_thermal_limit,
|
||||
.get_performance_level = smu_get_performance_level,
|
||||
.get_current_power_state = smu_get_current_power_state,
|
||||
.get_fan_speed_rpm = smu_get_fan_speed_rpm,
|
||||
|
|
|
@ -721,6 +721,18 @@ struct pptable_funcs {
|
|||
int (*read_sensor)(struct smu_context *smu, enum amd_pp_sensors sensor,
|
||||
void *data, uint32_t *size);
|
||||
|
||||
/**
|
||||
* @get_apu_thermal_limit: get apu core limit from smu
|
||||
* &limit: current limit temperature in millidegrees Celsius
|
||||
*/
|
||||
int (*get_apu_thermal_limit)(struct smu_context *smu, uint32_t *limit);
|
||||
|
||||
/**
|
||||
* @set_apu_thermal_limit: update all controllers with new limit
|
||||
* &limit: limit temperature to be setted, in millidegrees Celsius
|
||||
*/
|
||||
int (*set_apu_thermal_limit)(struct smu_context *smu, uint32_t limit);
|
||||
|
||||
/**
|
||||
* @pre_display_config_changed: Prepare GPU for a display configuration
|
||||
* change.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue