diff options
author | Dave Airlie <airlied@redhat.com> | 2010-12-06 18:20:40 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-01-04 22:45:30 -0500 |
commit | 5bcf719b7db0f9366cedaf102b081f99b1c325ae (patch) | |
tree | 6929d42e1d61a3b1bd7b130a37a80b99718e14aa | |
parent | 8d608aa6295242fe4c4b6105b8c59c6a5b232d89 (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.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_kms.c | 4 | ||||
-rw-r--r-- | include/drm/drmP.h | 6 |
10 files changed, 40 insertions, 13 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index a39794bac04b..2ec7d48fc4a8 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, | |||
236 | return -EBUSY; /* No exclusive opens */ | 236 | return -EBUSY; /* No exclusive opens */ |
237 | if (!drm_cpu_valid()) | 237 | if (!drm_cpu_valid()) |
238 | return -EINVAL; | 238 | return -EINVAL; |
239 | if (dev->switch_power_state != DRM_SWITCH_POWER_ON) | ||
240 | return -EINVAL; | ||
239 | 241 | ||
240 | DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); | 242 | DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); |
241 | 243 | ||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ec1f650f6fab..0568dbdc10ef 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_ | |||
1151 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | 1151 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; |
1152 | if (state == VGA_SWITCHEROO_ON) { | 1152 | if (state == VGA_SWITCHEROO_ON) { |
1153 | printk(KERN_INFO "i915: switched on\n"); | 1153 | printk(KERN_INFO "i915: switched on\n"); |
1154 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | ||
1154 | /* i915 resume handler doesn't set to D0 */ | 1155 | /* i915 resume handler doesn't set to D0 */ |
1155 | pci_set_power_state(dev->pdev, PCI_D0); | 1156 | pci_set_power_state(dev->pdev, PCI_D0); |
1156 | i915_resume(dev); | 1157 | i915_resume(dev); |
1158 | dev->switch_power_state = DRM_SWITCH_POWER_ON; | ||
1157 | } else { | 1159 | } else { |
1158 | printk(KERN_ERR "i915: switched off\n"); | 1160 | printk(KERN_ERR "i915: switched off\n"); |
1161 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | ||
1159 | i915_suspend(dev, pmm); | 1162 | i915_suspend(dev, pmm); |
1163 | dev->switch_power_state = DRM_SWITCH_POWER_OFF; | ||
1160 | } | 1164 | } |
1161 | } | 1165 | } |
1162 | 1166 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9eee6cf7901e..872493331988 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) | |||
271 | { | 271 | { |
272 | struct drm_i915_private *dev_priv = dev->dev_private; | 272 | struct drm_i915_private *dev_priv = dev->dev_private; |
273 | 273 | ||
274 | drm_kms_helper_poll_disable(dev); | ||
275 | |||
274 | pci_save_state(dev->pdev); | 276 | pci_save_state(dev->pdev); |
275 | 277 | ||
276 | /* If KMS is active, we do the leavevt stuff here */ | 278 | /* 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) | |||
307 | if (state.event == PM_EVENT_PRETHAW) | 309 | if (state.event == PM_EVENT_PRETHAW) |
308 | return 0; | 310 | return 0; |
309 | 311 | ||
310 | drm_kms_helper_poll_disable(dev); | 312 | |
313 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
314 | return 0; | ||
311 | 315 | ||
312 | error = i915_drm_freeze(dev); | 316 | error = i915_drm_freeze(dev); |
313 | if (error) | 317 | if (error) |
@@ -361,6 +365,9 @@ int i915_resume(struct drm_device *dev) | |||
361 | { | 365 | { |
362 | int ret; | 366 | int ret; |
363 | 367 | ||
368 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
369 | return 0; | ||
370 | |||
364 | if (pci_enable_device(dev->pdev)) | 371 | if (pci_enable_device(dev->pdev)) |
365 | return -EIO; | 372 | return -EIO; |
366 | 373 | ||
@@ -569,6 +576,9 @@ static int i915_pm_suspend(struct device *dev) | |||
569 | return -ENODEV; | 576 | return -ENODEV; |
570 | } | 577 | } |
571 | 578 | ||
579 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
580 | return 0; | ||
581 | |||
572 | error = i915_drm_freeze(drm_dev); | 582 | error = i915_drm_freeze(drm_dev); |
573 | if (error) | 583 | if (error) |
574 | return error; | 584 | return error; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index bb170570938b..13bb672a16f4 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) | |||
171 | if (pm_state.event == PM_EVENT_PRETHAW) | 171 | if (pm_state.event == PM_EVENT_PRETHAW) |
172 | return 0; | 172 | return 0; |
173 | 173 | ||
174 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
175 | return 0; | ||
176 | |||
174 | NV_INFO(dev, "Disabling fbcon acceleration...\n"); | 177 | NV_INFO(dev, "Disabling fbcon acceleration...\n"); |
175 | nouveau_fbcon_save_disable_accel(dev); | 178 | nouveau_fbcon_save_disable_accel(dev); |
176 | 179 | ||
@@ -254,6 +257,9 @@ nouveau_pci_resume(struct pci_dev *pdev) | |||
254 | struct drm_crtc *crtc; | 257 | struct drm_crtc *crtc; |
255 | int ret, i; | 258 | int ret, i; |
256 | 259 | ||
260 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
261 | return 0; | ||
262 | |||
257 | nouveau_fbcon_save_disable_accel(dev); | 263 | nouveau_fbcon_save_disable_accel(dev); |
258 | 264 | ||
259 | NV_INFO(dev, "We're back, enabling device...\n"); | 265 | 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 e81575687354..e59f5bcab1ad 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 { | |||
753 | 753 | ||
754 | struct nouveau_fbdev *nfbdev; | 754 | struct nouveau_fbdev *nfbdev; |
755 | struct apertures_struct *apertures; | 755 | struct apertures_struct *apertures; |
756 | |||
757 | bool powered_down; | ||
756 | }; | 758 | }; |
757 | 759 | ||
758 | static inline struct drm_nouveau_private * | 760 | 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 1b87eee22fa9..a54fc431fe98 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, | |||
596 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | 596 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; |
597 | if (state == VGA_SWITCHEROO_ON) { | 597 | if (state == VGA_SWITCHEROO_ON) { |
598 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); | 598 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); |
599 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | ||
599 | nouveau_pci_resume(pdev); | 600 | nouveau_pci_resume(pdev); |
600 | drm_kms_helper_poll_enable(dev); | 601 | drm_kms_helper_poll_enable(dev); |
602 | dev->switch_power_state = DRM_SWITCH_POWER_ON; | ||
601 | } else { | 603 | } else { |
602 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); | 604 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); |
605 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | ||
603 | drm_kms_helper_poll_disable(dev); | 606 | drm_kms_helper_poll_disable(dev); |
604 | nouveau_pci_suspend(pdev, pmm); | 607 | nouveau_pci_suspend(pdev, pmm); |
608 | dev->switch_power_state = DRM_SWITCH_POWER_OFF; | ||
605 | } | 609 | } |
606 | } | 610 | } |
607 | 611 | ||
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index d2697f8f2da8..140eaceab279 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -1167,7 +1167,6 @@ struct radeon_device { | |||
1167 | uint8_t audio_status_bits; | 1167 | uint8_t audio_status_bits; |
1168 | uint8_t audio_category_code; | 1168 | uint8_t audio_category_code; |
1169 | 1169 | ||
1170 | bool powered_down; | ||
1171 | struct notifier_block acpi_nb; | 1170 | struct notifier_block acpi_nb; |
1172 | /* only one userspace can use Hyperz features at a time */ | 1171 | /* only one userspace can use Hyperz features at a time */ |
1173 | struct drm_file *hyperz_filp; | 1172 | struct drm_file *hyperz_filp; |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 1a1017f0d9db..4ee0c53b28a7 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) | |||
642 | static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) | 642 | static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) |
643 | { | 643 | { |
644 | struct drm_device *dev = pci_get_drvdata(pdev); | 644 | struct drm_device *dev = pci_get_drvdata(pdev); |
645 | struct radeon_device *rdev = dev->dev_private; | ||
646 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | 645 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; |
647 | if (state == VGA_SWITCHEROO_ON) { | 646 | if (state == VGA_SWITCHEROO_ON) { |
648 | printk(KERN_INFO "radeon: switched on\n"); | 647 | printk(KERN_INFO "radeon: switched on\n"); |
649 | /* don't suspend or resume card normally */ | 648 | /* don't suspend or resume card normally */ |
650 | rdev->powered_down = false; | 649 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; |
651 | radeon_resume_kms(dev); | 650 | radeon_resume_kms(dev); |
651 | dev->switch_power_state = DRM_SWITCH_POWER_ON; | ||
652 | drm_kms_helper_poll_enable(dev); | 652 | drm_kms_helper_poll_enable(dev); |
653 | } else { | 653 | } else { |
654 | printk(KERN_INFO "radeon: switched off\n"); | 654 | printk(KERN_INFO "radeon: switched off\n"); |
655 | drm_kms_helper_poll_disable(dev); | 655 | drm_kms_helper_poll_disable(dev); |
656 | dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | ||
656 | radeon_suspend_kms(dev, pmm); | 657 | radeon_suspend_kms(dev, pmm); |
657 | /* don't suspend or resume card normally */ | 658 | dev->switch_power_state = DRM_SWITCH_POWER_OFF; |
658 | rdev->powered_down = true; | ||
659 | } | 659 | } |
660 | } | 660 | } |
661 | 661 | ||
@@ -842,7 +842,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) | |||
842 | } | 842 | } |
843 | rdev = dev->dev_private; | 843 | rdev = dev->dev_private; |
844 | 844 | ||
845 | if (rdev->powered_down) | 845 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) |
846 | return 0; | 846 | return 0; |
847 | 847 | ||
848 | /* turn off display hw */ | 848 | /* turn off display hw */ |
@@ -900,7 +900,7 @@ int radeon_resume_kms(struct drm_device *dev) | |||
900 | struct drm_connector *connector; | 900 | struct drm_connector *connector; |
901 | struct radeon_device *rdev = dev->dev_private; | 901 | struct radeon_device *rdev = dev->dev_private; |
902 | 902 | ||
903 | if (rdev->powered_down) | 903 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) |
904 | return 0; | 904 | return 0; |
905 | 905 | ||
906 | acquire_console_sem(); | 906 | acquire_console_sem(); |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 4bf423ca4c12..b2686334d46b 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) | |||
203 | */ | 203 | */ |
204 | int radeon_driver_firstopen_kms(struct drm_device *dev) | 204 | int radeon_driver_firstopen_kms(struct drm_device *dev) |
205 | { | 205 | { |
206 | struct radeon_device *rdev = dev->dev_private; | ||
207 | |||
208 | if (rdev->powered_down) | ||
209 | return -EINVAL; | ||
210 | return 0; | 206 | return 0; |
211 | } | 207 | } |
212 | 208 | ||
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0f14f94ed8f4..a4694c610330 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -1121,9 +1121,13 @@ struct drm_device { | |||
1121 | spinlock_t object_name_lock; | 1121 | spinlock_t object_name_lock; |
1122 | struct idr object_name_idr; | 1122 | struct idr object_name_idr; |
1123 | /*@} */ | 1123 | /*@} */ |
1124 | 1124 | int switch_power_state; | |
1125 | }; | 1125 | }; |
1126 | 1126 | ||
1127 | #define DRM_SWITCH_POWER_ON 0 | ||
1128 | #define DRM_SWITCH_POWER_OFF 1 | ||
1129 | #define DRM_SWITCH_POWER_CHANGING 2 | ||
1130 | |||
1127 | static __inline__ int drm_core_check_feature(struct drm_device *dev, | 1131 | static __inline__ int drm_core_check_feature(struct drm_device *dev, |
1128 | int feature) | 1132 | int feature) |
1129 | { | 1133 | { |