Commit d84300bf authored by Dave Airlie's avatar Dave Airlie

qxl: add suspend/resume/hibernate support.

This adds suspend/resume and hibernate support for the KMS driver. it evicts
all the objects, turns off the outputs, and waits for the hw to go idle,

On resume, it resets the memslots, rings, monitors object and forces modeset.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent b86487a6
...@@ -33,8 +33,9 @@ ...@@ -33,8 +33,9 @@
#include "drmP.h" #include "drmP.h"
#include "drm/drm.h" #include "drm/drm.h"
#include "drm_crtc_helper.h"
#include "qxl_drv.h" #include "qxl_drv.h"
#include "qxl_object.h"
extern int qxl_max_ioctls; extern int qxl_max_ioctls;
static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
...@@ -77,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev) ...@@ -77,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev); drm_put_dev(dev);
} }
static struct pci_driver qxl_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = qxl_pci_probe,
.remove = qxl_pci_remove,
};
static const struct file_operations qxl_fops = { static const struct file_operations qxl_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
...@@ -94,6 +88,130 @@ static const struct file_operations qxl_fops = { ...@@ -94,6 +88,130 @@ static const struct file_operations qxl_fops = {
.mmap = qxl_mmap, .mmap = qxl_mmap,
}; };
static int qxl_drm_freeze(struct drm_device *dev)
{
struct pci_dev *pdev = dev->pdev;
struct qxl_device *qdev = dev->dev_private;
struct drm_crtc *crtc;
drm_kms_helper_poll_disable(dev);
console_lock();
qxl_fbdev_set_suspend(qdev, 1);
console_unlock();
/* unpin the front buffers */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
if (crtc->enabled)
(*crtc_funcs->disable)(crtc);
}
qxl_destroy_monitors_object(qdev);
qxl_surf_evict(qdev);
qxl_vram_evict(qdev);
while (!qxl_check_idle(qdev->command_ring));
while (!qxl_check_idle(qdev->release_ring))
qxl_queue_garbage_collect(qdev, 1);
pci_save_state(pdev);
return 0;
}
static int qxl_drm_resume(struct drm_device *dev, bool thaw)
{
struct qxl_device *qdev = dev->dev_private;
qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
if (!thaw) {
qxl_reinit_memslots(qdev);
qxl_ring_init_hdr(qdev->release_ring);
}
qxl_create_monitors_object(qdev);
drm_helper_resume_force_mode(dev);
console_lock();
qxl_fbdev_set_suspend(qdev, 0);
console_unlock();
drm_kms_helper_poll_enable(dev);
return 0;
}
static int qxl_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int error;
error = qxl_drm_freeze(drm_dev);
if (error)
return error;
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int qxl_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if (pci_enable_device(pdev)) {
return -EIO;
}
return qxl_drm_resume(drm_dev, false);
}
static int qxl_pm_thaw(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
return qxl_drm_resume(drm_dev, true);
}
static int qxl_pm_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
return qxl_drm_freeze(drm_dev);
}
static int qxl_pm_restore(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct qxl_device *qdev = drm_dev->dev_private;
qxl_io_reset(qdev);
return qxl_drm_resume(drm_dev, false);
}
static const struct dev_pm_ops qxl_pm_ops = {
.suspend = qxl_pm_suspend,
.resume = qxl_pm_resume,
.freeze = qxl_pm_freeze,
.thaw = qxl_pm_thaw,
.poweroff = qxl_pm_freeze,
.restore = qxl_pm_restore,
};
static struct pci_driver qxl_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = qxl_pci_probe,
.remove = qxl_pci_remove,
.driver.pm = &qxl_pm_ops,
};
static struct drm_driver qxl_driver = { static struct drm_driver qxl_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | .driver_features = DRIVER_GEM | DRIVER_MODESET |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
......
...@@ -333,6 +333,7 @@ void qxl_bo_fini(struct qxl_device *qdev); ...@@ -333,6 +333,7 @@ void qxl_bo_fini(struct qxl_device *qdev);
void qxl_reinit_memslots(struct qxl_device *qdev); void qxl_reinit_memslots(struct qxl_device *qdev);
int qxl_surf_evict(struct qxl_device *qdev); int qxl_surf_evict(struct qxl_device *qdev);
int qxl_vram_evict(struct qxl_device *qdev);
struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
int element_size, int element_size,
......
...@@ -368,3 +368,8 @@ int qxl_surf_evict(struct qxl_device *qdev) ...@@ -368,3 +368,8 @@ int qxl_surf_evict(struct qxl_device *qdev)
{ {
return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0); return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
} }
int qxl_vram_evict(struct qxl_device *qdev)
{
return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_VRAM);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment