diff options
| author | 2008-07-29 22:23:50 +0000 | |
|---|---|---|
| committer | 2008-07-29 22:23:50 +0000 | |
| commit | bdca3b8a71f6f9e5464d6a949abd95390819be4f (patch) | |
| tree | d8757c0dfae32b312bb088e01efc12e3fbf3ec0f /sys/dev/pci/drm/drm_irq.c | |
| parent | Update list of supported machines. (diff) | |
| download | wireguard-openbsd-bdca3b8a71f6f9e5464d6a949abd95390819be4f.tar.xz wireguard-openbsd-bdca3b8a71f6f9e5464d6a949abd95390819be4f.zip | |
Update to DRM git.
Some stability fixes for radeon. The most part of this diff is related
to fixing up the VBLANK (vertical blank interrupt) handling. Now, if the
X driver supports the DRM_IOCTL_MODESET_CTL ioctl, (to be used when
changing the video modes), then allow the vblank to be disabled once
that ioctl has been called. Otherwise, keep the interrupt enabled at all
time, since disabling it otherwise will lead to problems.
Tested by a few. "no problem" on API/ABI deraadt@.
Diffstat (limited to 'sys/dev/pci/drm/drm_irq.c')
| -rw-r--r-- | sys/dev/pci/drm/drm_irq.c | 153 |
1 files changed, 69 insertions, 84 deletions
diff --git a/sys/dev/pci/drm/drm_irq.c b/sys/dev/pci/drm/drm_irq.c index e359abaefa7..30ba65057d6 100644 --- a/sys/dev/pci/drm/drm_irq.c +++ b/sys/dev/pci/drm/drm_irq.c @@ -37,6 +37,7 @@ irqreturn_t drm_irq_handler_wrap(DRM_IRQ_ARGS); void vblank_disable(void *); +void drm_update_vblank_count(struct drm_device *, int); void drm_locked_task(void *context, void *pending); int @@ -183,10 +184,15 @@ vblank_disable(void *arg) struct drm_device *dev = (struct drm_device*)arg; int i; + if (!dev->vblank_disable_allowed) + return; + for (i=0; i < dev->num_crtcs; i++){ DRM_SPINLOCK(&dev->vbl_lock); if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { + dev->last_vblank[i] = + dev->driver.get_vblank_counter(dev, i); dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } @@ -204,32 +210,21 @@ drm_vblank_cleanup(struct drm_device *dev) vblank_disable(dev); - if (dev->vbl_queue) - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * - dev->num_crtcs, M_DRM); + drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * + dev->num_crtcs, M_DRM); #if 0 /* disabled for now */ - if (dev-vbl_sigs) - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, - M_DRM); + drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, M_DRM); #endif - if (dev->_vblank_count) - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * - dev->num_crtcs, M_DRM); - if (dev->vblank_refcount) - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * - dev->num_crtcs, M_DRM); - if (dev->vblank_enabled) - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, M_DRM); - if (dev->last_vblank) - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * - dev->num_crtcs, M_DRM); - if (dev->vblank_premodeset) - drm_free(dev->vblank_premodeset, - sizeof(*dev->vblank_premodeset) * dev->num_crtcs, M_DRM); - if (dev->vblank_suspend) - drm_free(dev->vblank_suspend, - sizeof(*dev->vblank_suspend) * dev->num_crtcs, M_DRM); + drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * + dev->num_crtcs, M_DRM); + drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * + dev->num_crtcs, M_DRM); + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * + dev->num_crtcs, M_DRM); + drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * + dev->num_crtcs, M_DRM); + drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * + dev->num_crtcs, M_DRM); dev->num_crtcs = 0; DRM_SPINUNINIT(&dev->vbl_lock); @@ -259,23 +254,21 @@ drm_vblank_init(struct drm_device *dev, int num_crtcs) if ((dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(*dev->vblank_enabled), M_DRM)) == NULL) goto err; - if ((dev->last_vblank = drm_calloc(num_crtcs, sizeof(*dev->last_vblank), - M_DRM)) == NULL) - goto err; - if ((dev->vblank_premodeset = drm_calloc(num_crtcs, - sizeof(*dev->vblank_premodeset), M_DRM)) == NULL) + if ((dev->last_vblank = drm_calloc(num_crtcs, + sizeof(*dev->last_vblank), M_DRM)) == NULL) goto err; - if ((dev->vblank_suspend = drm_calloc(num_crtcs, - sizeof(*dev->vblank_suspend), M_DRM)) == NULL) + if ((dev->vblank_inmodeset = drm_calloc(num_crtcs, + sizeof(*dev->vblank_inmodeset), M_DRM)) == NULL) goto err; - /* Zero everything */ for (i = 0; i < num_crtcs; i++) { atomic_set(&dev->_vblank_count[i], 0); atomic_set(&dev->vblank_refcount[i], 0); } + dev->vblank_disable_allowed = 0; + return (0); err: @@ -294,27 +287,15 @@ drm_update_vblank_count(struct drm_device *dev, int crtc) { u_int32_t cur_vblank, diff; - if (dev->vblank_suspend[crtc]) - return; - /* - * Deal with the possibility of lost vblanks due to disabled interrupts - * counter overflow may have happened. + * Interrupt was disabled prior to this call, so deal with counter wrap + * note that we may have lost a full dev->max_vblank_count events if + * the register is small or the interrupts were off for a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK(&dev->vbl_lock); - 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; - } - } else { - diff = cur_vblank - dev->last_vblank[crtc]; - } - dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK(&dev->vbl_lock); + diff = cur_vblank - dev->last_vblank[crtc]; + if (cur_vblank < dev->last_vblank[crtc]) + diff += dev->max_vblank_count; atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -334,11 +315,12 @@ drm_vblank_get(struct drm_device *dev, int crtc) atomic_dec(&dev->vblank_refcount[crtc]); } else { dev->vblank_enabled[crtc] = 1; + drm_update_vblank_count(dev, crtc); } } DRM_SPINUNLOCK(&dev->vbl_lock); - return ret; + return (ret); } void @@ -348,7 +330,7 @@ drm_vblank_put(struct drm_device *dev, int crtc) /* Last user schedules interrupt disable */ atomic_dec(&dev->vblank_refcount[crtc]); if (dev->vblank_refcount[crtc] == 0) - timeout_add(&dev->vblank_disable_timer, 5*DRM_HZ); + timeout_add_sec(&dev->vblank_disable_timer, 5); DRM_SPINUNLOCK(&dev->vbl_lock); } @@ -358,36 +340,43 @@ drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) struct drm_modeset_ctl *modeset = data; int crtc, ret = 0; + /* not initialised yet, just noop */ + if (dev->num_crtcs == 0) + goto out; + crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { ret = EINVAL; goto out; } + /* If interrupts are enabled/disabled between calls to this ioctl then + * it can get nasty. So just grab a reference so that the interrupts + * keep going through the modeset + */ switch (modeset->cmd) { case _DRM_PRE_MODESET: - dev->vblank_premodeset[crtc] = - dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + if (dev->vblank_inmodeset[crtc] == 0) { + dev->vblank_inmodeset[crtc] = 1; + drm_vblank_get(dev, crtc); + } break; case _DRM_POST_MODESET: - if (dev->vblank_suspend[crtc]) { - uint32_t new = - dev->driver.get_vblank_counter(dev, crtc); - /* Compensate for spurious wraparound */ - if (new < dev->vblank_premodeset[crtc]) - atomic_sub(dev->max_vblank_count + new - - dev->vblank_premodeset[crtc], - &dev->_vblank_count[crtc]); + if (dev->vblank_inmodeset[crtc]) { + DRM_SPINLOCK(&dev->vbl_lock); + dev->vblank_disable_allowed = 1; + dev->vblank_inmodeset[crtc] = 0; + DRM_SPINUNLOCK(&dev->vbl_lock); + drm_vblank_put(dev, crtc); } - dev->vblank_suspend[crtc] = 0; break; default: ret = EINVAL; + break; } out: - return ret; + return (ret); } int @@ -405,7 +394,9 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) if (crtc >= dev->num_crtcs) return EINVAL; - drm_update_vblank_count(dev, crtc); + ret = drm_vblank_get(dev, crtc); + if (ret) + return (ret); seq = drm_vblank_count(dev,crtc); if (vblwait->request.type & _DRM_VBLANK_RELATIVE) { @@ -440,29 +431,22 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) #endif ret = EINVAL; } else { - if (!dev->vblank_suspend[crtc]) { - unsigned long cur_vblank; - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - while (ret == 0) { - DRM_SPINLOCK(&dev->vbl_lock); - if (((cur_vblank = drm_vblank_count(dev, crtc)) - - vblwait->request.sequence) <= (1 << 23)) { - DRM_SPINUNLOCK(&dev->vbl_lock); - break; - } - ret = msleep(&dev->vbl_queue[crtc], - &dev->vbl_lock, PZERO | PCATCH, - "drmvblq", 3 * DRM_HZ); + while (ret == 0) { + DRM_SPINLOCK(&dev->vbl_lock); + if ((drm_vblank_count(dev, crtc) + - vblwait->request.sequence) <= (1 << 23)) { DRM_SPINUNLOCK(&dev->vbl_lock); + break; } - drm_vblank_put(dev, crtc); + ret = msleep(&dev->vbl_queue[crtc], + &dev->vbl_lock, PZERO | PCATCH, + "drmvblq", 3 * DRM_HZ); + DRM_SPINUNLOCK(&dev->vbl_lock); } if (ret != EINTR) { struct timeval now; + microtime(&now); vblwait->reply.tval_sec = now.tv_sec; vblwait->reply.tval_usec = now.tv_usec; @@ -470,6 +454,7 @@ drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) } } + drm_vblank_put(dev, crtc); return (ret); } @@ -506,7 +491,7 @@ drm_vbl_send_signals(struct drm_device *dev, int crtc) void drm_handle_vblank(struct drm_device *dev, int crtc) { - drm_update_vblank_count(dev, crtc); + atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_vbl_send_signals(dev, crtc); } |
