diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-07-02 18:38:02 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-07-05 18:09:19 -0400 |
commit | 70d01a5ee29fcb23a6b5948227b1aee212922ade (patch) | |
tree | f2087b3fa9b4c6942686367c4390b4a04b6904c4 /drivers/gpu/drm | |
parent | 67d5ced503db5b44cb82f378c9cb3f0e77a94e7f (diff) |
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>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 52 |
2 files changed, 62 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 08cececb376d..b4681313646c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -1335,6 +1335,12 @@ enum radeon_pcie_gen { | |||
1335 | RADEON_PCIE_GEN_INVALID = 0xffff | 1335 | RADEON_PCIE_GEN_INVALID = 0xffff |
1336 | }; | 1336 | }; |
1337 | 1337 | ||
1338 | enum radeon_dpm_forced_level { | ||
1339 | RADEON_DPM_FORCED_LEVEL_AUTO = 0, | ||
1340 | RADEON_DPM_FORCED_LEVEL_LOW = 1, | ||
1341 | RADEON_DPM_FORCED_LEVEL_HIGH = 2, | ||
1342 | }; | ||
1343 | |||
1338 | struct radeon_dpm { | 1344 | struct radeon_dpm { |
1339 | struct radeon_ps *ps; | 1345 | struct radeon_ps *ps; |
1340 | /* number of valid power states */ | 1346 | /* number of valid power states */ |
@@ -1374,6 +1380,8 @@ struct radeon_dpm { | |||
1374 | bool uvd_active; | 1380 | bool uvd_active; |
1375 | /* thermal handling */ | 1381 | /* thermal handling */ |
1376 | struct radeon_dpm_thermal thermal; | 1382 | struct radeon_dpm_thermal thermal; |
1383 | /* forced levels */ | ||
1384 | enum radeon_dpm_forced_level forced_level; | ||
1377 | }; | 1385 | }; |
1378 | 1386 | ||
1379 | void radeon_dpm_enable_power_state(struct radeon_device *rdev, | 1387 | void radeon_dpm_enable_power_state(struct radeon_device *rdev, |
@@ -1669,6 +1677,7 @@ struct radeon_asic { | |||
1669 | u32 (*get_mclk)(struct radeon_device *rdev, bool low); | 1677 | u32 (*get_mclk)(struct radeon_device *rdev, bool low); |
1670 | void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps); | 1678 | void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps); |
1671 | void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m); | 1679 | void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m); |
1680 | int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level); | ||
1672 | } dpm; | 1681 | } dpm; |
1673 | /* pageflipping */ | 1682 | /* pageflipping */ |
1674 | struct { | 1683 | struct { |
@@ -2436,6 +2445,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); | |||
2436 | #define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l)) | 2445 | #define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l)) |
2437 | #define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps)) | 2446 | #define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps)) |
2438 | #define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m)) | 2447 | #define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m)) |
2448 | #define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l)) | ||
2439 | 2449 | ||
2440 | /* Common functions */ | 2450 | /* Common functions */ |
2441 | /* AGP */ | 2451 | /* AGP */ |
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index aaafb931922f..2557e8bab5cc 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -468,9 +468,57 @@ fail: | |||
468 | return count; | 468 | return count; |
469 | } | 469 | } |
470 | 470 | ||
471 | static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev, | ||
472 | struct device_attribute *attr, | ||
473 | char *buf) | ||
474 | { | ||
475 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); | ||
476 | struct radeon_device *rdev = ddev->dev_private; | ||
477 | enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; | ||
478 | |||
479 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
480 | (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" : | ||
481 | (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high"); | ||
482 | } | ||
483 | |||
484 | static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev, | ||
485 | struct device_attribute *attr, | ||
486 | const char *buf, | ||
487 | size_t count) | ||
488 | { | ||
489 | struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); | ||
490 | struct radeon_device *rdev = ddev->dev_private; | ||
491 | enum radeon_dpm_forced_level level; | ||
492 | int ret = 0; | ||
493 | |||
494 | mutex_lock(&rdev->pm.mutex); | ||
495 | if (strncmp("low", buf, strlen("low")) == 0) { | ||
496 | level = RADEON_DPM_FORCED_LEVEL_LOW; | ||
497 | } else if (strncmp("high", buf, strlen("high")) == 0) { | ||
498 | level = RADEON_DPM_FORCED_LEVEL_HIGH; | ||
499 | } else if (strncmp("auto", buf, strlen("auto")) == 0) { | ||
500 | level = RADEON_DPM_FORCED_LEVEL_AUTO; | ||
501 | } else { | ||
502 | mutex_unlock(&rdev->pm.mutex); | ||
503 | count = -EINVAL; | ||
504 | goto fail; | ||
505 | } | ||
506 | if (rdev->asic->dpm.force_performance_level) { | ||
507 | ret = radeon_dpm_force_performance_level(rdev, level); | ||
508 | if (ret) | ||
509 | count = -EINVAL; | ||
510 | } | ||
511 | mutex_unlock(&rdev->pm.mutex); | ||
512 | fail: | ||
513 | return count; | ||
514 | } | ||
515 | |||
471 | static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); | 516 | static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); |
472 | static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); | 517 | static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); |
473 | static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); | 518 | static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); |
519 | static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, | ||
520 | radeon_get_dpm_forced_performance_level, | ||
521 | radeon_set_dpm_forced_performance_level); | ||
474 | 522 | ||
475 | static ssize_t radeon_hwmon_show_temp(struct device *dev, | 523 | static ssize_t radeon_hwmon_show_temp(struct device *dev, |
476 | struct device_attribute *attr, | 524 | struct device_attribute *attr, |
@@ -1066,6 +1114,9 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) | |||
1066 | ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); | 1114 | ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); |
1067 | if (ret) | 1115 | if (ret) |
1068 | DRM_ERROR("failed to create device file for dpm state\n"); | 1116 | DRM_ERROR("failed to create device file for dpm state\n"); |
1117 | ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); | ||
1118 | if (ret) | ||
1119 | DRM_ERROR("failed to create device file for dpm state\n"); | ||
1069 | /* XXX: these are noops for dpm but are here for backwards compat */ | 1120 | /* XXX: these are noops for dpm but are here for backwards compat */ |
1070 | ret = device_create_file(rdev->dev, &dev_attr_power_profile); | 1121 | ret = device_create_file(rdev->dev, &dev_attr_power_profile); |
1071 | if (ret) | 1122 | if (ret) |
@@ -1170,6 +1221,7 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev) | |||
1170 | mutex_unlock(&rdev->pm.mutex); | 1221 | mutex_unlock(&rdev->pm.mutex); |
1171 | 1222 | ||
1172 | device_remove_file(rdev->dev, &dev_attr_power_dpm_state); | 1223 | device_remove_file(rdev->dev, &dev_attr_power_dpm_state); |
1224 | device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); | ||
1173 | /* XXX backwards compat */ | 1225 | /* XXX backwards compat */ |
1174 | device_remove_file(rdev->dev, &dev_attr_power_profile); | 1226 | device_remove_file(rdev->dev, &dev_attr_power_profile); |
1175 | device_remove_file(rdev->dev, &dev_attr_power_method); | 1227 | device_remove_file(rdev->dev, &dev_attr_power_method); |