#include "drmP.h"
#include "drm/drm.h"
-
+#include "drm_crtc_helper.h"
#include "qxl_drv.h"
+#include "qxl_object.h"
extern int qxl_max_ioctls;
static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
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 = {
.owner = THIS_MODULE,
.open = drm_open,
.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 = {
.driver_features = DRIVER_GEM | DRIVER_MODESET |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,