diff options
-rw-r--r-- | bsd-core/drmP.h | 4 | ||||
-rw-r--r-- | bsd-core/drm_irq.c | 102 |
2 files changed, 42 insertions, 64 deletions
diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 6b91a76b..326b2202 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -798,8 +798,7 @@ struct drm_device { /* for wraparound handling */ int *vblank_enabled; /* so we don't call enable more than */ /* once per disable */ - u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ - int *vblank_suspend; /* Don't wait while crtc is likely disabled */ + int *vblank_inmodeset; /* Display driver is setting mode */ struct callout vblank_disable_timer; u32 max_vblank_count; /* size of vblank counter register */ int num_crtcs; @@ -932,7 +931,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc); u32 drm_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_get(struct drm_device *dev, int crtc); void drm_vblank_put(struct drm_device *dev, int crtc); -void drm_update_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); int drm_vblank_init(struct drm_device *dev, int num_crtcs); void drm_vbl_send_signals(struct drm_device *dev, int crtc); diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 4b515ad8..6e21d41c 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -124,9 +124,7 @@ static void drm_vblank_cleanup(struct drm_device *dev) dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; @@ -169,14 +167,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->last_vblank) goto err; - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), + dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - - dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_suspend) + if (!dev->vblank_inmodeset) goto err; /* Zero per-crtc vblank stuff */ @@ -340,13 +333,10 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) return atomic_read(&dev->_vblank_count[crtc]); } -void drm_update_vblank_count(struct drm_device *dev, int crtc) +static void drm_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; - if (dev->vblank_suspend[crtc]) - return; - /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -355,21 +345,13 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); + diff = cur_vblank - dev->last_vblank[crtc]; if (cur_vblank < dev->last_vblank[crtc]) { - if (cur_vblank == dev->last_vblank[crtc] - 1) { - diff = 0; - } else { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; - } + diff += dev->max_vblank_count; DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", crtc, dev->last_vblank[crtc], cur_vblank, diff); - } else { - diff = cur_vblank - dev->last_vblank[crtc]; } - dev->last_vblank[crtc] = cur_vblank; DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); @@ -408,7 +390,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) - callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, + callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } @@ -418,39 +400,40 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, { struct drm_modeset_ctl *modeset = data; unsigned long irqflags; - u32 new, diff; int crtc, ret = 0; + /* If drm_vblank_init() hasn't been called yet, just no-op */ + if (!dev->num_crtcs) + goto out; + crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { ret = EINVAL; goto out; } + /* + * To avoid all the problems that might happen if interrupts + * were enabled/disabled around or between these calls, we just + * have the kernel take a reference on the CRTC (just once though + * to avoid corrupting the count if multiple, mismatch calls occur), + * so that interrupts remain enabled in the interim. + */ switch (modeset->cmd) { case _DRM_PRE_MODESET: - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - if (!dev->vblank_enabled[crtc]) { - dev->vblank_premodeset[crtc] = - dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + if (!dev->vblank_inmodeset[crtc]) { + dev->vblank_inmodeset[crtc] = 1; + drm_vblank_get(dev, crtc); } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - new = dev->driver.get_vblank_counter(dev, crtc); - if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { - if (new > dev->vblank_premodeset[crtc]) - diff = dev->vblank_premodeset[crtc] - new; - else - diff = new; - atomic_add(diff, &dev->_vblank_count[crtc]); + if (dev->vblank_inmodeset[crtc]) { + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + dev->vblank_inmodeset[crtc] = 0; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + drm_vblank_put(dev, crtc); } - dev->vblank_suspend[crtc] = 0; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; default: ret = EINVAL; @@ -484,6 +467,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (crtc >= dev->num_crtcs) return EINVAL; + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -493,7 +479,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr case _DRM_VBLANK_ABSOLUTE: break; default: - return EINVAL; + ret = EINVAL; + goto done; } if ((flags & _DRM_VBLANK_NEXTONMISS) && @@ -508,9 +495,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (vbl_sig == NULL) return ENOMEM; - if (dev->vblank_suspend[crtc]) - return EBUSY; - vbl_sig->sequence = vblwait->request.sequence; vbl_sig->signo = vblwait->request.signal; vbl_sig->pid = DRM_CURRENTPID; @@ -524,19 +508,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr #endif ret = EINVAL; } else { - if (!dev->vblank_suspend[crtc]) { - DRM_LOCK(); - /* shared code returns -errno */ - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - ((drm_vblank_count(dev, crtc) - - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); - DRM_UNLOCK(); - } + DRM_LOCK(); + /* shared code returns -errno */ + + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) + - vblwait->request.sequence) <= (1 << 23))); + DRM_UNLOCK(); if (ret != EINTR) { struct timeval now; @@ -548,6 +526,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr } } +done: + drm_vblank_put(dev, crtc); return ret; } |