summaryrefslogtreecommitdiffstats
path: root/sys/dev/drm/drm_irq.c
diff options
context:
space:
mode:
authorrnoland <rnoland@FreeBSD.org>2009-03-25 01:50:56 +0000
committerrnoland <rnoland@FreeBSD.org>2009-03-25 01:50:56 +0000
commitf7c1e3a6bf90bc3fdd51ddf7eecb359853ac736d (patch)
tree8599bb8357c64fcf42d71ae1f422d57cc6bc7644 /sys/dev/drm/drm_irq.c
parent6a5678040a495b6236de7ac15c5f38e2e596b313 (diff)
downloadFreeBSD-src-f7c1e3a6bf90bc3fdd51ddf7eecb359853ac736d.zip
FreeBSD-src-f7c1e3a6bf90bc3fdd51ddf7eecb359853ac736d.tar.gz
Rework the management of vblank interrupts a bit.
When a vt switch occurs the irq handler is uninstalled. Interrupts and the state tracking of what was enabled/disabled wasn't working properly. This should resolve the reports of "slow windows" after a vt switch, among other things. The radeon 2d driver seems to work a bit more correctly than the Intel driver. With the Intel driver, vblank interrupts will be enabled at system startup and will only be disabled after an additional modeset (vt switch, dpms, randr event). With this patch, I am able to run glxgears synced to vblank and vt switch while it is running without ill effects. MFC after: 3 days
Diffstat (limited to 'sys/dev/drm/drm_irq.c')
-rw-r--r--sys/dev/drm/drm_irq.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/sys/dev/drm/drm_irq.c b/sys/dev/drm/drm_irq.c
index da3ccfb..44b8100 100644
--- a/sys/dev/drm/drm_irq.c
+++ b/sys/dev/drm/drm_irq.c
@@ -80,13 +80,14 @@ static void vblank_disable_fn(void *arg)
}
callout_deactivate(&dev->vblank_disable_timer);
- DRM_DEBUG("vblank_disable_allowed=%d\n", dev->vblank_disable_allowed);
+ DRM_DEBUG("vblank_disable: %s\n", dev->vblank_disable_allowed ?
+ "allowed" : "denied");
if (!dev->vblank_disable_allowed)
return;
for (i = 0; i < dev->num_crtcs; i++) {
if (atomic_read(&dev->vblank[i].refcount) == 0 &&
- dev->vblank[i].enabled) {
+ dev->vblank[i].enabled && !dev->vblank[i].inmodeset) {
DRM_DEBUG("disabling vblank on crtc %d\n", i);
dev->vblank[i].last =
dev->driver->get_vblank_counter(dev, i);
@@ -149,7 +150,7 @@ err:
int drm_irq_install(struct drm_device *dev)
{
- int retcode;
+ int crtc, retcode;
if (dev->irq == 0 || dev->dev_private == NULL)
return EINVAL;
@@ -186,6 +187,17 @@ int drm_irq_install(struct drm_device *dev)
DRM_LOCK();
dev->driver->irq_postinstall(dev);
DRM_UNLOCK();
+ if (dev->driver->enable_vblank) {
+ DRM_SPINLOCK(&dev->vbl_lock);
+ for( crtc = 0 ; crtc < dev->num_crtcs ; crtc++) {
+ if (dev->driver->enable_vblank(dev, crtc) == 0) {
+ dev->vblank[crtc].enabled = 1;
+ }
+ }
+ callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
+ (timeout_t *)vblank_disable_fn, (void *)dev);
+ DRM_SPINUNLOCK(&dev->vbl_lock);
+ }
return 0;
err:
@@ -212,9 +224,9 @@ int drm_irq_uninstall(struct drm_device *dev)
for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
if (dev->vblank[crtc].enabled) {
DRM_WAKEUP(&dev->vblank[crtc].queue);
- dev->vblank[crtc].enabled = 0;
dev->vblank[crtc].last =
- dev->driver->get_vblank_counter(dev, crtc);
+ dev->driver->get_vblank_counter(dev, crtc);
+ dev->vblank[crtc].enabled = 0;
}
}
DRM_SPINUNLOCK(&dev->vbl_lock);
@@ -320,9 +332,11 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
/* Last user schedules interrupt disable */
atomic_subtract_acq_int(&dev->vblank[crtc].refcount, 1);
+ DRM_SPINLOCK(&dev->vbl_lock);
if (dev->vblank[crtc].refcount == 0)
callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
(timeout_t *)vblank_disable_fn, (void *)dev);
+ DRM_SPINUNLOCK(&dev->vbl_lock);
}
int drm_modeset_ctl(struct drm_device *dev, void *data,
@@ -449,31 +463,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
} else {
DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
vblwait->request.sequence, crtc);
- for ( ret = 0 ; !ret && !((drm_vblank_count(dev, crtc) -
- vblwait->request.sequence) <= (1 << 23)) ; ) {
- mtx_lock(&dev->irq_lock);
- if (!((drm_vblank_count(dev, crtc) -
- vblwait->request.sequence) <= (1 << 23)))
- ret = mtx_sleep(&dev->vblank[crtc].queue,
- &dev->irq_lock, PCATCH, "vblwtq",
- 3 * DRM_HZ);
- mtx_unlock(&dev->irq_lock);
- }
-
- if (ret == ERESTART) {
- DRM_DEBUG("restarting syscall\n");
- return ret;
+ mtx_lock(&dev->irq_lock);
+ dev->vblank[crtc].last = vblwait->request.sequence;
+ for ( ret = 0 ; !ret && !(((drm_vblank_count(dev, crtc) -
+ vblwait->request.sequence) <= (1 << 23)) ||
+ !dev->irq_enabled) ; ) {
+ ret = mtx_sleep(&dev->vblank[crtc].queue,
+ &dev->irq_lock, PCATCH, "vblwtq",
+ 3 * DRM_HZ);
}
+ mtx_unlock(&dev->irq_lock);
- if (ret != EINTR) {
+ if (ret != EINTR && ret != ERESTART) {
struct timeval now;
microtime(&now);
vblwait->reply.tval_sec = now.tv_sec;
vblwait->reply.tval_usec = now.tv_usec;
vblwait->reply.sequence = drm_vblank_count(dev, crtc);
- DRM_DEBUG("returning %d to client\n",
- vblwait->reply.sequence);
+ DRM_DEBUG("returning %d to client, irq_enabled %d\n",
+ vblwait->reply.sequence, dev->irq_enabled);
} else {
DRM_DEBUG("vblank wait interrupted by signal\n");
}
OpenPOWER on IntegriCloud