summaryrefslogtreecommitdiff
path: root/sys/dev/pci/drm
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2009-04-04 19:39:08 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2009-04-04 19:39:08 +0000
commitf1aca551c2548d05823faab2f604b40afacbf40b (patch)
tree49802ff14edc703a2dadd6b855bebf95518270ca /sys/dev/pci/drm
parentbf884d4ee6db52ac6270df38429cbc1f7b7c7692 (diff)
A couple of fixes (based mostly on stuff from upstream) to stop
breaking vblanks over suspend. Firstly, when we turn off the irq, wait up anyone waiting on vblanks, and prepare for the fact that interrupts are going off. Secondly, only reduce the refcount for vblanks over modeset if they were actually turned on. Fixes gl apps running while you suspend an x40 (as in they still work when it comes back).
Diffstat (limited to 'sys/dev/pci/drm')
-rw-r--r--sys/dev/pci/drm/drm_irq.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/sys/dev/pci/drm/drm_irq.c b/sys/dev/pci/drm/drm_irq.c
index ba9d1b8f82d..50fa58d826b 100644
--- a/sys/dev/pci/drm/drm_irq.c
+++ b/sys/dev/pci/drm/drm_irq.c
@@ -88,6 +88,7 @@ err:
int
drm_irq_uninstall(struct drm_device *dev)
{
+ int i;
DRM_LOCK();
if (!dev->irq_enabled) {
@@ -98,6 +99,20 @@ drm_irq_uninstall(struct drm_device *dev)
dev->irq_enabled = 0;
DRM_UNLOCK();
+ /*
+ * Ick. we're about to turn of vblanks, so make sure anyone waiting
+ * on them gets woken up. Also make sure we update state correctly
+ * so that we can continue refcounting correctly.
+ */
+ mtx_enter(&dev->vbl_lock);
+ for (i = 0; i < dev->num_crtcs; i++) {
+ wakeup(&dev->vblank[i]);
+ dev->vblank[i].vbl_enabled = 0;
+ dev->vblank[i].last_vblank =
+ dev->driver->get_vblank_counter(dev, i);
+ }
+ mtx_leave(&dev->vbl_lock);
+
DRM_DEBUG("irq=%d\n", dev->irq);
dev->driver->irq_uninstall(dev);
@@ -238,9 +253,6 @@ drm_vblank_get(struct drm_device *dev, int crtc)
void
drm_vblank_put(struct drm_device *dev, int crtc)
{
- if (dev->irq_enabled == 0)
- return;
-
mtx_enter(&dev->vbl_lock);
/* Last user schedules interrupt disable */
atomic_dec(&dev->vblank[crtc].vbl_refcount);
@@ -274,18 +286,20 @@ drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
case _DRM_PRE_MODESET:
if (dev->vblank[crtc].vbl_inmodeset == 0) {
mtx_enter(&dev->vbl_lock);
- dev->vblank[crtc].vbl_inmodeset = 1;
+ dev->vblank[crtc].vbl_inmodeset = 0x1;
mtx_leave(&dev->vbl_lock);
- drm_vblank_get(dev, crtc);
+ if (drm_vblank_get(dev, crtc) == 0)
+ dev->vblank[crtc].vbl_inmodeset |= 0x2;
}
break;
case _DRM_POST_MODESET:
if (dev->vblank[crtc].vbl_inmodeset) {
mtx_enter(&dev->vbl_lock);
dev->vblank_disable_allowed = 1;
- dev->vblank[crtc].vbl_inmodeset = 0;
mtx_leave(&dev->vbl_lock);
- drm_vblank_put(dev, crtc);
+ if (dev->vblank[crtc].vbl_inmodeset & 0x2)
+ drm_vblank_put(dev, crtc);
+ dev->vblank[crtc].vbl_inmodeset = 0;
}
break;
default:
@@ -332,8 +346,9 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
ret = EINVAL;
} else {
DRM_WAIT_ON(ret, &dev->vblank[crtc], &dev->vbl_lock, 3 * hz,
- "drmvblq", (drm_vblank_count(dev, crtc) -
- vblwait->request.sequence) <= (1 << 23));
+ "drmvblq", ((drm_vblank_count(dev, crtc) -
+ vblwait->request.sequence) <= (1 << 23)) ||
+ dev->irq_enabled == 0);
if (ret != EINTR) {
struct timeval now;