summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-12-07 09:20:40 +1000
committerDave Airlie <airlied@redhat.com>2011-01-05 13:45:30 +1000
commit5bcf719b7db0f9366cedaf102b081f99b1c325ae (patch)
tree6929d42e1d61a3b1bd7b130a37a80b99718e14aa
parent8d608aa6295242fe4c4b6105b8c59c6a5b232d89 (diff)
drm/switcheroo: track state of switch in drivers.
We need to track the state of the switch in drivers, so that after s/r we don't resume the card we've explicitly switched off before. Also don't allow a userspace open to occur if we've switched the gpu off. Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_fops.c2
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c4
-rw-r--r--include/drm/drmP.h6
10 files changed, 40 insertions, 13 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index a39794bac04..2ec7d48fc4a 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -236,6 +236,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
return -EBUSY; /* No exclusive opens */
if (!drm_cpu_valid())
return -EINVAL;
+ if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
+ return -EINVAL;
DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ec1f650f6fa..0568dbdc10e 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1151,12 +1151,16 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_INFO "i915: switched on\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
printk(KERN_ERR "i915: switched off\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
i915_suspend(dev, pmm);
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 9eee6cf7901..87249333198 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -271,6 +271,8 @@ static int i915_drm_freeze(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ drm_kms_helper_poll_disable(dev);
+
pci_save_state(dev->pdev);
/* If KMS is active, we do the leavevt stuff here */
@@ -307,7 +309,9 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
if (state.event == PM_EVENT_PRETHAW)
return 0;
- drm_kms_helper_poll_disable(dev);
+
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
error = i915_drm_freeze(dev);
if (error)
@@ -361,6 +365,9 @@ int i915_resume(struct drm_device *dev)
{
int ret;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
if (pci_enable_device(dev->pdev))
return -EIO;
@@ -569,6 +576,9 @@ static int i915_pm_suspend(struct device *dev)
return -ENODEV;
}
+ if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
error = i915_drm_freeze(drm_dev);
if (error)
return error;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index bb170570938..13bb672a16f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -171,6 +171,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
if (pm_state.event == PM_EVENT_PRETHAW)
return 0;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
NV_INFO(dev, "Disabling fbcon acceleration...\n");
nouveau_fbcon_save_disable_accel(dev);
@@ -254,6 +257,9 @@ nouveau_pci_resume(struct pci_dev *pdev)
struct drm_crtc *crtc;
int ret, i;
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
nouveau_fbcon_save_disable_accel(dev);
NV_INFO(dev, "We're back, enabling device...\n");
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index e8157568735..e59f5bcab1a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -753,6 +753,8 @@ struct drm_nouveau_private {
struct nouveau_fbdev *nfbdev;
struct apertures_struct *apertures;
+
+ bool powered_down;
};
static inline struct drm_nouveau_private *
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 1b87eee22fa..a54fc431fe9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -596,12 +596,16 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
nouveau_pci_resume(pdev);
drm_kms_helper_poll_enable(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(dev);
nouveau_pci_suspend(pdev, pmm);
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index d2697f8f2da..140eaceab27 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1167,7 +1167,6 @@ struct radeon_device {
uint8_t audio_status_bits;
uint8_t audio_category_code;
- bool powered_down;
struct notifier_block acpi_nb;
/* only one userspace can use Hyperz features at a time */
struct drm_file *hyperz_filp;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 1a1017f0d9d..4ee0c53b28a 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -642,20 +642,20 @@ void radeon_check_arguments(struct radeon_device *rdev)
static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
- struct radeon_device *rdev = dev->dev_private;
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_INFO "radeon: switched on\n");
/* don't suspend or resume card normally */
- rdev->powered_down = false;
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
radeon_resume_kms(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
drm_kms_helper_poll_enable(dev);
} else {
printk(KERN_INFO "radeon: switched off\n");
drm_kms_helper_poll_disable(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
radeon_suspend_kms(dev, pmm);
- /* don't suspend or resume card normally */
- rdev->powered_down = true;
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
@@ -842,7 +842,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
}
rdev = dev->dev_private;
- if (rdev->powered_down)
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
/* turn off display hw */
@@ -900,7 +900,7 @@ int radeon_resume_kms(struct drm_device *dev)
struct drm_connector *connector;
struct radeon_device *rdev = dev->dev_private;
- if (rdev->powered_down)
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
acquire_console_sem();
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 4bf423ca4c1..b2686334d46 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -203,10 +203,6 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*/
int radeon_driver_firstopen_kms(struct drm_device *dev)
{
- struct radeon_device *rdev = dev->dev_private;
-
- if (rdev->powered_down)
- return -EINVAL;
return 0;
}
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 0f14f94ed8f..a4694c61033 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1121,9 +1121,13 @@ struct drm_device {
spinlock_t object_name_lock;
struct idr object_name_idr;
/*@} */
-
+ int switch_power_state;
};
+#define DRM_SWITCH_POWER_ON 0
+#define DRM_SWITCH_POWER_OFF 1
+#define DRM_SWITCH_POWER_CHANGING 2
+
static __inline__ int drm_core_check_feature(struct drm_device *dev,
int feature)
{