diff mbox

drm/radeon/pm: don't allow debugfs/sysfs access when PX card is off (v2)

Message ID 1400541689-23264-1-git-send-email-alexander.deucher@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Deucher May 19, 2014, 11:21 p.m. UTC
When the PX card is off don't try and access it. Avoid hw access
to the card while it's off (e.g., reading back invalid temperature).

v2: be less strict

bug:
https://bugzilla.kernel.org/show_bug.cgi?id=76321

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
---
 drivers/gpu/drm/radeon/radeon_pm.c | 42 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

Comments

Ben Hutchings May 21, 2014, 1:31 a.m. UTC | #1
On Mon, 2014-05-19 at 19:21 -0400, Alex Deucher wrote:
> When the PX card is off don't try and access it. Avoid hw access
> to the card while it's off (e.g., reading back invalid temperature).
> 
> v2: be less strict
> 
> bug:
> https://bugzilla.kernel.org/show_bug.cgi?id=76321

I count 8 copies of the same condition.  It seems like it deserves to be
a function.

Ben.

> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> Cc: stable@vger.kernel.org
> ---
>  drivers/gpu/drm/radeon/radeon_pm.c | 42 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 41 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index f30b842..53d6e1b 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -361,6 +361,11 @@ static ssize_t radeon_set_pm_profile(struct device *dev,
>  	struct drm_device *ddev = dev_get_drvdata(dev);
>  	struct radeon_device *rdev = ddev->dev_private;
>  
> +	/* Can't set profile when the card is off */
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
> +		return -EINVAL;
> +
>  	mutex_lock(&rdev->pm.mutex);
>  	if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
>  		if (strncmp("default", buf, strlen("default")) == 0)
> @@ -409,6 +414,13 @@ static ssize_t radeon_set_pm_method(struct device *dev,
>  	struct drm_device *ddev = dev_get_drvdata(dev);
>  	struct radeon_device *rdev = ddev->dev_private;
>  
> +	/* Can't set method when the card is off */
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
> +		count = -EINVAL;
> +		goto fail;
> +	}
> +
>  	/* we don't support the legacy modes with dpm */
>  	if (rdev->pm.pm_method == PM_METHOD_DPM) {
>  		count = -EINVAL;
> @@ -446,6 +458,10 @@ static ssize_t radeon_get_dpm_state(struct device *dev,
>  	struct radeon_device *rdev = ddev->dev_private;
>  	enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
>  
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
> +		return snprintf(buf, PAGE_SIZE, "off\n");
> +
>  	return snprintf(buf, PAGE_SIZE, "%s\n",
>  			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
>  			(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
> @@ -459,6 +475,11 @@ static ssize_t radeon_set_dpm_state(struct device *dev,
>  	struct drm_device *ddev = dev_get_drvdata(dev);
>  	struct radeon_device *rdev = ddev->dev_private;
>  
> +	/* Can't set dpm state when the card is off */
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
> +		return -EINVAL;
> +
>  	mutex_lock(&rdev->pm.mutex);
>  	if (strncmp("battery", buf, strlen("battery")) == 0)
>  		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
> @@ -485,6 +506,10 @@ static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
>  	struct radeon_device *rdev = ddev->dev_private;
>  	enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
>  
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
> +		return snprintf(buf, PAGE_SIZE, "off\n");
> +
>  	return snprintf(buf, PAGE_SIZE, "%s\n",
>  			(level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
>  			(level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
> @@ -500,6 +525,11 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
>  	enum radeon_dpm_forced_level level;
>  	int ret = 0;
>  
> +	/* Can't force performance level when the card is off */
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
> +		return -EINVAL;
> +
>  	mutex_lock(&rdev->pm.mutex);
>  	if (strncmp("low", buf, strlen("low")) == 0) {
>  		level = RADEON_DPM_FORCED_LEVEL_LOW;
> @@ -538,8 +568,14 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
>  				      char *buf)
>  {
>  	struct radeon_device *rdev = dev_get_drvdata(dev);
> +	struct drm_device *ddev = rdev->ddev;
>  	int temp;
>  
> +	/* Can't get temperature when the card is off */
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
> +		return -EINVAL;
> +
>  	if (rdev->asic->pm.get_temperature)
>  		temp = radeon_get_temperature(rdev);
>  	else
> @@ -1614,8 +1650,12 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
>  	struct drm_info_node *node = (struct drm_info_node *) m->private;
>  	struct drm_device *dev = node->minor->dev;
>  	struct radeon_device *rdev = dev->dev_private;
> +	struct drm_device *ddev = rdev->ddev;
>  
> -	if (rdev->pm.dpm_enabled) {
> +	if  ((rdev->flags & RADEON_IS_PX) &&
> +	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
> +		seq_printf(m, "PX asic powered off\n");
> +	} else if (rdev->pm.dpm_enabled) {
>  		mutex_lock(&rdev->pm.mutex);
>  		if (rdev->asic->dpm.debugfs_print_current_performance_level)
>  			radeon_dpm_debugfs_print_current_performance_level(rdev, m);
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index f30b842..53d6e1b 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -361,6 +361,11 @@  static ssize_t radeon_set_pm_profile(struct device *dev,
 	struct drm_device *ddev = dev_get_drvdata(dev);
 	struct radeon_device *rdev = ddev->dev_private;
 
+	/* Can't set profile when the card is off */
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+		return -EINVAL;
+
 	mutex_lock(&rdev->pm.mutex);
 	if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
 		if (strncmp("default", buf, strlen("default")) == 0)
@@ -409,6 +414,13 @@  static ssize_t radeon_set_pm_method(struct device *dev,
 	struct drm_device *ddev = dev_get_drvdata(dev);
 	struct radeon_device *rdev = ddev->dev_private;
 
+	/* Can't set method when the card is off */
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
+		count = -EINVAL;
+		goto fail;
+	}
+
 	/* we don't support the legacy modes with dpm */
 	if (rdev->pm.pm_method == PM_METHOD_DPM) {
 		count = -EINVAL;
@@ -446,6 +458,10 @@  static ssize_t radeon_get_dpm_state(struct device *dev,
 	struct radeon_device *rdev = ddev->dev_private;
 	enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
 
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+		return snprintf(buf, PAGE_SIZE, "off\n");
+
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 			(pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
 			(pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
@@ -459,6 +475,11 @@  static ssize_t radeon_set_dpm_state(struct device *dev,
 	struct drm_device *ddev = dev_get_drvdata(dev);
 	struct radeon_device *rdev = ddev->dev_private;
 
+	/* Can't set dpm state when the card is off */
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+		return -EINVAL;
+
 	mutex_lock(&rdev->pm.mutex);
 	if (strncmp("battery", buf, strlen("battery")) == 0)
 		rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
@@ -485,6 +506,10 @@  static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
 	struct radeon_device *rdev = ddev->dev_private;
 	enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
 
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+		return snprintf(buf, PAGE_SIZE, "off\n");
+
 	return snprintf(buf, PAGE_SIZE, "%s\n",
 			(level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
 			(level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
@@ -500,6 +525,11 @@  static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
 	enum radeon_dpm_forced_level level;
 	int ret = 0;
 
+	/* Can't force performance level when the card is off */
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+		return -EINVAL;
+
 	mutex_lock(&rdev->pm.mutex);
 	if (strncmp("low", buf, strlen("low")) == 0) {
 		level = RADEON_DPM_FORCED_LEVEL_LOW;
@@ -538,8 +568,14 @@  static ssize_t radeon_hwmon_show_temp(struct device *dev,
 				      char *buf)
 {
 	struct radeon_device *rdev = dev_get_drvdata(dev);
+	struct drm_device *ddev = rdev->ddev;
 	int temp;
 
+	/* Can't get temperature when the card is off */
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+		return -EINVAL;
+
 	if (rdev->asic->pm.get_temperature)
 		temp = radeon_get_temperature(rdev);
 	else
@@ -1614,8 +1650,12 @@  static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	struct radeon_device *rdev = dev->dev_private;
+	struct drm_device *ddev = rdev->ddev;
 
-	if (rdev->pm.dpm_enabled) {
+	if  ((rdev->flags & RADEON_IS_PX) &&
+	     (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
+		seq_printf(m, "PX asic powered off\n");
+	} else if (rdev->pm.dpm_enabled) {
 		mutex_lock(&rdev->pm.mutex);
 		if (rdev->asic->dpm.debugfs_print_current_performance_level)
 			radeon_dpm_debugfs_print_current_performance_level(rdev, m);