Skip to content

Commit

Permalink
drm/switcheroo: track state of switch in drivers.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dave Airlie committed Jan 5, 2011
1 parent 8d608aa commit 5bcf719
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 13 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/drm_fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
12 changes: 11 additions & 1 deletion drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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");
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions drivers/gpu/drm/radeon/radeon_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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();
Expand Down
4 changes: 0 additions & 4 deletions drivers/gpu/drm/radeon/radeon_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
6 changes: 5 additions & 1 deletion include/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit 5bcf719

Please sign in to comment.