aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-07-04 01:02:33 -0400
committerDave Airlie <airlied@redhat.com>2013-07-04 20:44:18 -0400
commitd84300bf793471cc20c7553601c45d6f70dd2b1e (patch)
treefd30ee57cf7c8ede42123ed4c61a7d9cfd4d1269
parentb86487a6b671ff7107fbf6d3ff10c2da970cd1c3 (diff)
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: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c134
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h1
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c5
3 files changed, 132 insertions, 8 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index 00e57b76f4f5..df0b577a6608 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -33,8 +33,9 @@
33 33
34#include "drmP.h" 34#include "drmP.h"
35#include "drm/drm.h" 35#include "drm/drm.h"
36 36#include "drm_crtc_helper.h"
37#include "qxl_drv.h" 37#include "qxl_drv.h"
38#include "qxl_object.h"
38 39
39extern int qxl_max_ioctls; 40extern int qxl_max_ioctls;
40static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { 41static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
@@ -77,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev)
77 drm_put_dev(dev); 78 drm_put_dev(dev);
78} 79}
79 80
80static struct pci_driver qxl_pci_driver = {
81 .name = DRIVER_NAME,
82 .id_table = pciidlist,
83 .probe = qxl_pci_probe,
84 .remove = qxl_pci_remove,
85};
86
87static const struct file_operations qxl_fops = { 81static const struct file_operations qxl_fops = {
88 .owner = THIS_MODULE, 82 .owner = THIS_MODULE,
89 .open = drm_open, 83 .open = drm_open,
@@ -94,6 +88,130 @@ static const struct file_operations qxl_fops = {
94 .mmap = qxl_mmap, 88 .mmap = qxl_mmap,
95}; 89};
96 90
91static int qxl_drm_freeze(struct drm_device *dev)
92{
93 struct pci_dev *pdev = dev->pdev;
94 struct qxl_device *qdev = dev->dev_private;
95 struct drm_crtc *crtc;
96
97 drm_kms_helper_poll_disable(dev);
98
99 console_lock();
100 qxl_fbdev_set_suspend(qdev, 1);
101 console_unlock();
102
103 /* unpin the front buffers */
104 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
105 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
106 if (crtc->enabled)
107 (*crtc_funcs->disable)(crtc);
108 }
109
110 qxl_destroy_monitors_object(qdev);
111 qxl_surf_evict(qdev);
112 qxl_vram_evict(qdev);
113
114 while (!qxl_check_idle(qdev->command_ring));
115 while (!qxl_check_idle(qdev->release_ring))
116 qxl_queue_garbage_collect(qdev, 1);
117
118 pci_save_state(pdev);
119
120 return 0;
121}
122
123static int qxl_drm_resume(struct drm_device *dev, bool thaw)
124{
125 struct qxl_device *qdev = dev->dev_private;
126
127 qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
128 if (!thaw) {
129 qxl_reinit_memslots(qdev);
130 qxl_ring_init_hdr(qdev->release_ring);
131 }
132
133 qxl_create_monitors_object(qdev);
134 drm_helper_resume_force_mode(dev);
135
136 console_lock();
137 qxl_fbdev_set_suspend(qdev, 0);
138 console_unlock();
139
140 drm_kms_helper_poll_enable(dev);
141 return 0;
142}
143
144static int qxl_pm_suspend(struct device *dev)
145{
146 struct pci_dev *pdev = to_pci_dev(dev);
147 struct drm_device *drm_dev = pci_get_drvdata(pdev);
148 int error;
149
150 error = qxl_drm_freeze(drm_dev);
151 if (error)
152 return error;
153
154 pci_disable_device(pdev);
155 pci_set_power_state(pdev, PCI_D3hot);
156 return 0;
157}
158
159static int qxl_pm_resume(struct device *dev)
160{
161 struct pci_dev *pdev = to_pci_dev(dev);
162 struct drm_device *drm_dev = pci_get_drvdata(pdev);
163
164 pci_set_power_state(pdev, PCI_D0);
165 pci_restore_state(pdev);
166 if (pci_enable_device(pdev)) {
167 return -EIO;
168 }
169
170 return qxl_drm_resume(drm_dev, false);
171}
172
173static int qxl_pm_thaw(struct device *dev)
174{
175 struct pci_dev *pdev = to_pci_dev(dev);
176 struct drm_device *drm_dev = pci_get_drvdata(pdev);
177
178 return qxl_drm_resume(drm_dev, true);
179}
180
181static int qxl_pm_freeze(struct device *dev)
182{
183 struct pci_dev *pdev = to_pci_dev(dev);
184 struct drm_device *drm_dev = pci_get_drvdata(pdev);
185
186 return qxl_drm_freeze(drm_dev);
187}
188
189static int qxl_pm_restore(struct device *dev)
190{
191 struct pci_dev *pdev = to_pci_dev(dev);
192 struct drm_device *drm_dev = pci_get_drvdata(pdev);
193 struct qxl_device *qdev = drm_dev->dev_private;
194
195 qxl_io_reset(qdev);
196 return qxl_drm_resume(drm_dev, false);
197}
198
199static const struct dev_pm_ops qxl_pm_ops = {
200 .suspend = qxl_pm_suspend,
201 .resume = qxl_pm_resume,
202 .freeze = qxl_pm_freeze,
203 .thaw = qxl_pm_thaw,
204 .poweroff = qxl_pm_freeze,
205 .restore = qxl_pm_restore,
206};
207static struct pci_driver qxl_pci_driver = {
208 .name = DRIVER_NAME,
209 .id_table = pciidlist,
210 .probe = qxl_pci_probe,
211 .remove = qxl_pci_remove,
212 .driver.pm = &qxl_pm_ops,
213};
214
97static struct drm_driver qxl_driver = { 215static struct drm_driver qxl_driver = {
98 .driver_features = DRIVER_GEM | DRIVER_MODESET | 216 .driver_features = DRIVER_GEM | DRIVER_MODESET |
99 DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, 217 DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 70a67862673a..aacb791464a3 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -333,6 +333,7 @@ void qxl_bo_fini(struct qxl_device *qdev);
333 333
334void qxl_reinit_memslots(struct qxl_device *qdev); 334void qxl_reinit_memslots(struct qxl_device *qdev);
335int qxl_surf_evict(struct qxl_device *qdev); 335int qxl_surf_evict(struct qxl_device *qdev);
336int qxl_vram_evict(struct qxl_device *qdev);
336 337
337struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, 338struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
338 int element_size, 339 int element_size,
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index 62a046e4a036..1191fe7788c9 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -368,3 +368,8 @@ int qxl_surf_evict(struct qxl_device *qdev)
368{ 368{
369 return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0); 369 return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
370} 370}
371
372int qxl_vram_evict(struct qxl_device *qdev)
373{
374 return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_VRAM);
375}