drm/radeon/dpm: add infrastructure to force performance levels
This allows you to force specific power levels within a power state. Due to hardware restrictions between generations, the interface is limited to the following 3 selections: auto: all levels enabled low: forced to the lowest power level high: forced to the highest power level Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
67d5ced503
commit
70d01a5ee2
2 changed files with 62 additions and 0 deletions
|
@ -1335,6 +1335,12 @@ enum radeon_pcie_gen {
|
||||||
RADEON_PCIE_GEN_INVALID = 0xffff
|
RADEON_PCIE_GEN_INVALID = 0xffff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum radeon_dpm_forced_level {
|
||||||
|
RADEON_DPM_FORCED_LEVEL_AUTO = 0,
|
||||||
|
RADEON_DPM_FORCED_LEVEL_LOW = 1,
|
||||||
|
RADEON_DPM_FORCED_LEVEL_HIGH = 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct radeon_dpm {
|
struct radeon_dpm {
|
||||||
struct radeon_ps *ps;
|
struct radeon_ps *ps;
|
||||||
/* number of valid power states */
|
/* number of valid power states */
|
||||||
|
@ -1374,6 +1380,8 @@ struct radeon_dpm {
|
||||||
bool uvd_active;
|
bool uvd_active;
|
||||||
/* thermal handling */
|
/* thermal handling */
|
||||||
struct radeon_dpm_thermal thermal;
|
struct radeon_dpm_thermal thermal;
|
||||||
|
/* forced levels */
|
||||||
|
enum radeon_dpm_forced_level forced_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
void radeon_dpm_enable_power_state(struct radeon_device *rdev,
|
void radeon_dpm_enable_power_state(struct radeon_device *rdev,
|
||||||
|
@ -1669,6 +1677,7 @@ struct radeon_asic {
|
||||||
u32 (*get_mclk)(struct radeon_device *rdev, bool low);
|
u32 (*get_mclk)(struct radeon_device *rdev, bool low);
|
||||||
void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps);
|
void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps);
|
||||||
void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m);
|
void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m);
|
||||||
|
int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level);
|
||||||
} dpm;
|
} dpm;
|
||||||
/* pageflipping */
|
/* pageflipping */
|
||||||
struct {
|
struct {
|
||||||
|
@ -2436,6 +2445,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
|
||||||
#define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l))
|
#define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l))
|
||||||
#define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps))
|
#define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps))
|
||||||
#define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m))
|
#define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m))
|
||||||
|
#define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l))
|
||||||
|
|
||||||
/* Common functions */
|
/* Common functions */
|
||||||
/* AGP */
|
/* AGP */
|
||||||
|
|
|
@ -468,9 +468,57 @@ fail:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
|
||||||
|
struct radeon_device *rdev = ddev->dev_private;
|
||||||
|
enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
|
||||||
|
|
||||||
|
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||||
|
(level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
|
||||||
|
(level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
|
||||||
|
struct radeon_device *rdev = ddev->dev_private;
|
||||||
|
enum radeon_dpm_forced_level level;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&rdev->pm.mutex);
|
||||||
|
if (strncmp("low", buf, strlen("low")) == 0) {
|
||||||
|
level = RADEON_DPM_FORCED_LEVEL_LOW;
|
||||||
|
} else if (strncmp("high", buf, strlen("high")) == 0) {
|
||||||
|
level = RADEON_DPM_FORCED_LEVEL_HIGH;
|
||||||
|
} else if (strncmp("auto", buf, strlen("auto")) == 0) {
|
||||||
|
level = RADEON_DPM_FORCED_LEVEL_AUTO;
|
||||||
|
} else {
|
||||||
|
mutex_unlock(&rdev->pm.mutex);
|
||||||
|
count = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (rdev->asic->dpm.force_performance_level) {
|
||||||
|
ret = radeon_dpm_force_performance_level(rdev, level);
|
||||||
|
if (ret)
|
||||||
|
count = -EINVAL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&rdev->pm.mutex);
|
||||||
|
fail:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
|
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
|
||||||
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
|
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
|
||||||
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
|
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
|
||||||
|
static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
|
||||||
|
radeon_get_dpm_forced_performance_level,
|
||||||
|
radeon_set_dpm_forced_performance_level);
|
||||||
|
|
||||||
static ssize_t radeon_hwmon_show_temp(struct device *dev,
|
static ssize_t radeon_hwmon_show_temp(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
|
@ -1064,6 +1112,9 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev)
|
||||||
|
|
||||||
if (rdev->pm.num_power_states > 1) {
|
if (rdev->pm.num_power_states > 1) {
|
||||||
ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
|
ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
|
||||||
|
if (ret)
|
||||||
|
DRM_ERROR("failed to create device file for dpm state\n");
|
||||||
|
ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
|
||||||
if (ret)
|
if (ret)
|
||||||
DRM_ERROR("failed to create device file for dpm state\n");
|
DRM_ERROR("failed to create device file for dpm state\n");
|
||||||
/* XXX: these are noops for dpm but are here for backwards compat */
|
/* XXX: these are noops for dpm but are here for backwards compat */
|
||||||
|
@ -1170,6 +1221,7 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev)
|
||||||
mutex_unlock(&rdev->pm.mutex);
|
mutex_unlock(&rdev->pm.mutex);
|
||||||
|
|
||||||
device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
|
device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
|
||||||
|
device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
|
||||||
/* XXX backwards compat */
|
/* XXX backwards compat */
|
||||||
device_remove_file(rdev->dev, &dev_attr_power_profile);
|
device_remove_file(rdev->dev, &dev_attr_power_profile);
|
||||||
device_remove_file(rdev->dev, &dev_attr_power_method);
|
device_remove_file(rdev->dev, &dev_attr_power_method);
|
||||||
|
|
Loading…
Add table
Reference in a new issue