diff options
Diffstat (limited to 'drivers/gpu/drm/drm_vblank.c')
-rw-r--r-- | drivers/gpu/drm/drm_vblank.c | 313 |
1 files changed, 168 insertions, 145 deletions
diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 2d5ce690d214..b18e1efbbae1 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -25,6 +25,7 @@ */ #include <linux/export.h> +#include <linux/kthread.h> #include <linux/moduleparam.h> #include <drm/drm_crtc.h> @@ -194,7 +195,7 @@ static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe) */ static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe) { - WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0); + drm_WARN_ON_ONCE(dev, drm_max_vblank_count(dev, pipe) != 0); return 0; } @@ -203,7 +204,7 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); - if (WARN_ON(!crtc)) + if (drm_WARN_ON(dev, !crtc)) return 0; if (crtc->funcs->get_vblank_counter) @@ -311,15 +312,15 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, * frame/field duration. */ - DRM_DEBUG_VBL("crtc %u: Calculating number of vblanks." - " diff_ns = %lld, framedur_ns = %d)\n", - pipe, (long long) diff_ns, framedur_ns); + drm_dbg_vbl(dev, "crtc %u: Calculating number of vblanks." + " diff_ns = %lld, framedur_ns = %d)\n", + pipe, (long long)diff_ns, framedur_ns); diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); if (diff == 0 && in_vblank_irq) - DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored\n", - pipe); + drm_dbg_vbl(dev, "crtc %u: Redundant vblirq ignored\n", + pipe); } else { /* some kind of default for drivers w/o accurate vbl timestamping */ diff = in_vblank_irq ? 1 : 0; @@ -335,18 +336,19 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, * random large forward jumps of the software vblank counter. */ if (diff > 1 && (vblank->inmodeset & 0x2)) { - DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u" - " due to pre-modeset.\n", pipe, diff); + drm_dbg_vbl(dev, + "clamping vblank bump to 1 on crtc %u: diffr=%u" + " due to pre-modeset.\n", pipe, diff); diff = 1; } - DRM_DEBUG_VBL("updating vblank count on crtc %u:" - " current=%llu, diff=%u, hw=%u hw_last=%u\n", - pipe, (unsigned long long)atomic64_read(&vblank->count), - diff, cur_vblank, vblank->last); + drm_dbg_vbl(dev, "updating vblank count on crtc %u:" + " current=%llu, diff=%u, hw=%u hw_last=%u\n", + pipe, (unsigned long long)atomic64_read(&vblank->count), + diff, cur_vblank, vblank->last); if (diff == 0) { - WARN_ON_ONCE(cur_vblank != vblank->last); + drm_WARN_ON_ONCE(dev, cur_vblank != vblank->last); return; } @@ -362,12 +364,12 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, store_vblank(dev, pipe, diff, t_vblank, cur_vblank); } -static u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe) +u64 drm_vblank_count(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; u64 count; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return 0; count = atomic64_read(&vblank->count); @@ -402,9 +404,9 @@ u64 drm_crtc_accurate_vblank_count(struct drm_crtc *crtc) u64 vblank; unsigned long flags; - WARN_ONCE(drm_debug_enabled(DRM_UT_VBL) && - !crtc->funcs->get_vblank_timestamp, - "This function requires support for accurate vblank timestamps."); + drm_WARN_ONCE(dev, drm_debug_enabled(DRM_UT_VBL) && + !crtc->funcs->get_vblank_timestamp, + "This function requires support for accurate vblank timestamps."); spin_lock_irqsave(&dev->vblank_time_lock, flags); @@ -422,7 +424,7 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe) if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); - if (WARN_ON(!crtc)) + if (drm_WARN_ON(dev, !crtc)) return; if (crtc->funcs->disable_vblank) @@ -483,7 +485,7 @@ static void vblank_disable_fn(struct timer_list *t) spin_lock_irqsave(&dev->vbl_lock, irqflags); if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) { - DRM_DEBUG("disabling vblank on crtc %u\n", pipe); + drm_dbg_core(dev, "disabling vblank on crtc %u\n", pipe); drm_vblank_disable_and_save(dev, pipe); } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -491,16 +493,13 @@ static void vblank_disable_fn(struct timer_list *t) static void drm_vblank_init_release(struct drm_device *dev, void *ptr) { - unsigned int pipe; - - for (pipe = 0; pipe < dev->num_crtcs; pipe++) { - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct drm_vblank_crtc *vblank = ptr; - WARN_ON(READ_ONCE(vblank->enabled) && - drm_core_check_feature(dev, DRIVER_MODESET)); + drm_WARN_ON(dev, READ_ONCE(vblank->enabled) && + drm_core_check_feature(dev, DRIVER_MODESET)); - del_timer_sync(&vblank->disable_timer); - } + drm_vblank_destroy_worker(vblank); + del_timer_sync(&vblank->disable_timer); } /** @@ -510,7 +509,7 @@ static void drm_vblank_init_release(struct drm_device *dev, void *ptr) * * This function initializes vblank support for @num_crtcs display pipelines. * Cleanup is handled automatically through a cleanup function added with - * drmm_add_action(). + * drmm_add_action_or_reset(). * * Returns: * Zero on success or a negative error code on failure. @@ -529,10 +528,6 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) dev->num_crtcs = num_crtcs; - ret = drmm_add_action(dev, drm_vblank_init_release, NULL); - if (ret) - return ret; - for (i = 0; i < num_crtcs; i++) { struct drm_vblank_crtc *vblank = &dev->vblank[i]; @@ -541,9 +536,16 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs) init_waitqueue_head(&vblank->queue); timer_setup(&vblank->disable_timer, vblank_disable_fn, 0); seqlock_init(&vblank->seqlock); - } - DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); + ret = drmm_add_action_or_reset(dev, drm_vblank_init_release, + vblank); + if (ret) + return ret; + + ret = drm_vblank_worker_init(vblank); + if (ret) + return ret; + } return 0; } @@ -606,10 +608,10 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, int linedur_ns = 0, framedur_ns = 0; int dotclock = mode->crtc_clock; - if (!dev->num_crtcs) + if (!drm_dev_has_vblank(dev)) return; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; /* Valid dotclock? */ @@ -629,19 +631,21 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc, */ if (mode->flags & DRM_MODE_FLAG_INTERLACE) framedur_ns /= 2; - } else - DRM_ERROR("crtc %u: Can't calculate constants, dotclock = 0!\n", - crtc->base.id); + } else { + drm_err(dev, "crtc %u: Can't calculate constants, dotclock = 0!\n", + crtc->base.id); + } vblank->linedur_ns = linedur_ns; vblank->framedur_ns = framedur_ns; vblank->hwmode = *mode; - DRM_DEBUG("crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", - crtc->base.id, mode->crtc_htotal, - mode->crtc_vtotal, mode->crtc_vdisplay); - DRM_DEBUG("crtc %u: clock %d kHz framedur %d linedur %d\n", - crtc->base.id, dotclock, framedur_ns, linedur_ns); + drm_dbg_core(dev, + "crtc %u: hwmode: htotal %d, vtotal %d, vdisplay %d\n", + crtc->base.id, mode->crtc_htotal, + mode->crtc_vtotal, mode->crtc_vdisplay); + drm_dbg_core(dev, "crtc %u: clock %d kHz framedur %d linedur %d\n", + crtc->base.id, dotclock, framedur_ns, linedur_ns); } EXPORT_SYMBOL(drm_calc_timestamping_constants); @@ -694,13 +698,13 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( int delta_ns, duration_ns; if (pipe >= dev->num_crtcs) { - DRM_ERROR("Invalid crtc %u\n", pipe); + drm_err(dev, "Invalid crtc %u\n", pipe); return false; } /* Scanout position query not supported? Should not happen. */ if (!get_scanout_position) { - DRM_ERROR("Called from CRTC w/o get_scanout_position()!?\n"); + drm_err(dev, "Called from CRTC w/o get_scanout_position()!?\n"); return false; } @@ -713,8 +717,9 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( * Happens during initial modesetting of a crtc. */ if (mode->crtc_clock == 0) { - DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe); - WARN_ON_ONCE(drm_drv_uses_atomic_modeset(dev)); + drm_dbg_core(dev, "crtc %u: Noop due to uninitialized mode.\n", + pipe); + drm_WARN_ON_ONCE(dev, drm_drv_uses_atomic_modeset(dev)); return false; } @@ -737,8 +742,9 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( /* Return as no-op if scanout query unsupported or failed. */ if (!vbl_status) { - DRM_DEBUG("crtc %u : scanoutpos query failed.\n", - pipe); + drm_dbg_core(dev, + "crtc %u : scanoutpos query failed.\n", + pipe); return false; } @@ -752,8 +758,9 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( /* Noisy system timing? */ if (i == DRM_TIMESTAMP_MAXRETRIES) { - DRM_DEBUG("crtc %u: Noisy timestamp %d us > %d us [%d reps].\n", - pipe, duration_ns/1000, *max_error/1000, i); + drm_dbg_core(dev, + "crtc %u: Noisy timestamp %d us > %d us [%d reps].\n", + pipe, duration_ns / 1000, *max_error / 1000, i); } /* Return upper bound of timestamp precision error. */ @@ -777,11 +784,12 @@ drm_crtc_vblank_helper_get_vblank_timestamp_internal( ts_etime = ktime_to_timespec64(etime); ts_vblank_time = ktime_to_timespec64(*vblank_time); - DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %lld.%06ld -> %lld.%06ld [e %d us, %d rep]\n", - pipe, hpos, vpos, - (u64)ts_etime.tv_sec, ts_etime.tv_nsec / 1000, - (u64)ts_vblank_time.tv_sec, ts_vblank_time.tv_nsec / 1000, - duration_ns / 1000, i); + drm_dbg_vbl(dev, + "crtc %u : v p(%d,%d)@ %lld.%06ld -> %lld.%06ld [e %d us, %d rep]\n", + pipe, hpos, vpos, + (u64)ts_etime.tv_sec, ts_etime.tv_nsec / 1000, + (u64)ts_vblank_time.tv_sec, ts_vblank_time.tv_nsec / 1000, + duration_ns / 1000, i); return true; } @@ -925,7 +933,7 @@ static u64 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, u64 vblank_count; unsigned int seq; - if (WARN_ON(pipe >= dev->num_crtcs)) { + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) { *vblanktime = 0; return 0; } @@ -1066,7 +1074,7 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc, unsigned int pipe = drm_crtc_index(crtc); ktime_t now; - if (dev->num_crtcs > 0) { + if (drm_dev_has_vblank(dev)) { seq = drm_vblank_count_and_time(dev, pipe, &now); } else { seq = 0; @@ -1083,7 +1091,7 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe) if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); - if (WARN_ON(!crtc)) + if (drm_WARN_ON(dev, !crtc)) return 0; if (crtc->funcs->enable_vblank) @@ -1113,7 +1121,8 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) * prevent double-accounting of same vblank interval. */ ret = __enable_vblank(dev, pipe); - DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret); + drm_dbg_core(dev, "enabling vblank on crtc %u, ret: %d\n", + pipe, ret); if (ret) { atomic_dec(&vblank->refcount); } else { @@ -1132,16 +1141,16 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) return ret; } -static int drm_vblank_get(struct drm_device *dev, unsigned int pipe) +int drm_vblank_get(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; int ret = 0; - if (!dev->num_crtcs) + if (!drm_dev_has_vblank(dev)) return -EINVAL; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return -EINVAL; spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -1175,14 +1184,14 @@ int drm_crtc_vblank_get(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_get); -static void drm_vblank_put(struct drm_device *dev, unsigned int pipe) +void drm_vblank_put(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; - if (WARN_ON(atomic_read(&vblank->refcount) == 0)) + if (drm_WARN_ON(dev, atomic_read(&vblank->refcount) == 0)) return; /* Last user schedules interrupt disable */ @@ -1227,11 +1236,12 @@ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) int ret; u64 last; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; ret = drm_vblank_get(dev, pipe); - if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", pipe, ret)) + if (drm_WARN(dev, ret, "vblank not available on crtc %i, ret=%i\n", + pipe, ret)) return; last = drm_vblank_count(dev, pipe); @@ -1240,7 +1250,7 @@ void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe) last != drm_vblank_count(dev, pipe), msecs_to_jiffies(100)); - WARN(ret == 0, "vblank wait timed out on crtc %i\n", pipe); + drm_WARN(dev, ret == 0, "vblank wait timed out on crtc %i\n", pipe); drm_vblank_put(dev, pipe); } @@ -1277,19 +1287,21 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_pending_vblank_event *e, *t; - ktime_t now; - unsigned long irqflags; u64 seq; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; - spin_lock_irqsave(&dev->event_lock, irqflags); + /* + * Grab event_lock early to prevent vblank work from being scheduled + * while we're in the middle of shutting down vblank interrupts + */ + spin_lock_irq(&dev->event_lock); spin_lock(&dev->vbl_lock); - DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", - pipe, vblank->enabled, vblank->inmodeset); + drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n", + pipe, vblank->enabled, vblank->inmodeset); /* Avoid redundant vblank disables without previous * drm_crtc_vblank_on(). */ @@ -1314,18 +1326,25 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != pipe) continue; - DRM_DEBUG("Sending premature vblank event on disable: " - "wanted %llu, current %llu\n", - e->sequence, seq); + drm_dbg_core(dev, "Sending premature vblank event on disable: " + "wanted %llu, current %llu\n", + e->sequence, seq); list_del(&e->base.link); drm_vblank_put(dev, pipe); send_vblank_event(dev, e, seq, now); } - spin_unlock_irqrestore(&dev->event_lock, irqflags); + + /* Cancel any leftover pending vblank work */ + drm_vblank_cancel_pending_works(vblank); + + spin_unlock_irq(&dev->event_lock); /* Will be reset by the modeset helpers when re-enabling the crtc by * calling drm_calc_timestamping_constants(). */ vblank->hwmode.crtc_clock = 0; + + /* Wait for any vblank work that's still executing to finish */ + drm_vblank_flush_worker(vblank); } EXPORT_SYMBOL(drm_crtc_vblank_off); @@ -1344,11 +1363,10 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); void drm_crtc_vblank_reset(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - unsigned long irqflags; unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - spin_lock_irqsave(&dev->vbl_lock, irqflags); + spin_lock_irq(&dev->vbl_lock); /* * Prevent subsequent drm_vblank_get() from enabling the vblank * interrupt by bumping the refcount. @@ -1357,9 +1375,10 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc) atomic_inc(&vblank->refcount); vblank->inmodeset = 1; } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + spin_unlock_irq(&dev->vbl_lock); - WARN_ON(!list_empty(&dev->vblank_event_list)); + drm_WARN_ON(dev, !list_empty(&dev->vblank_event_list)); + drm_WARN_ON(dev, !list_empty(&vblank->pending_work)); } EXPORT_SYMBOL(drm_crtc_vblank_reset); @@ -1387,8 +1406,8 @@ void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - WARN_ON(dev->max_vblank_count); - WARN_ON(!READ_ONCE(vblank->inmodeset)); + drm_WARN_ON(dev, dev->max_vblank_count); + drm_WARN_ON(dev, !READ_ONCE(vblank->inmodeset)); vblank->max_vblank_count = max_vblank_count; } @@ -1409,14 +1428,13 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - unsigned long irqflags; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; - spin_lock_irqsave(&dev->vbl_lock, irqflags); - DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", - pipe, vblank->enabled, vblank->inmodeset); + spin_lock_irq(&dev->vbl_lock); + drm_dbg_vbl(dev, "crtc %d, vblank enabled %d, inmodeset %d\n", + pipe, vblank->enabled, vblank->inmodeset); /* Drop our private "prevent drm_vblank_get" refcount */ if (vblank->inmodeset) { @@ -1431,8 +1449,8 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc) * user wishes vblank interrupts to be enabled all the time. */ if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0) - WARN_ON(drm_vblank_enable(dev, pipe)); - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + drm_WARN_ON(dev, drm_vblank_enable(dev, pipe)); + spin_unlock_irq(&dev->vbl_lock); } EXPORT_SYMBOL(drm_crtc_vblank_on); @@ -1458,15 +1476,16 @@ void drm_vblank_restore(struct drm_device *dev, unsigned int pipe) u32 cur_vblank, diff = 1; int count = DRM_TIMESTAMP_MAXRETRIES; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; assert_spin_locked(&dev->vbl_lock); assert_spin_locked(&dev->vblank_time_lock); vblank = &dev->vblank[pipe]; - WARN_ONCE(drm_debug_enabled(DRM_UT_VBL) && !vblank->framedur_ns, - "Cannot compute missed vblanks without frame duration\n"); + drm_WARN_ONCE(dev, + drm_debug_enabled(DRM_UT_VBL) && !vblank->framedur_ns, + "Cannot compute missed vblanks without frame duration\n"); framedur_ns = vblank->framedur_ns; do { @@ -1479,8 +1498,9 @@ void drm_vblank_restore(struct drm_device *dev, unsigned int pipe) diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns); - DRM_DEBUG_VBL("missed %d vblanks in %lld ns, frame duration=%d ns, hw_diff=%d\n", - diff, diff_ns, framedur_ns, cur_vblank - vblank->last); + drm_dbg_vbl(dev, + "missed %d vblanks in %lld ns, frame duration=%d ns, hw_diff=%d\n", + diff, diff_ns, framedur_ns, cur_vblank - vblank->last); store_vblank(dev, pipe, diff, t_vblank, cur_vblank); } EXPORT_SYMBOL(drm_vblank_restore); @@ -1507,10 +1527,10 @@ static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; /* vblank is not initialized (IRQ not installed ?), or has been freed */ - if (!dev->num_crtcs) + if (!drm_dev_has_vblank(dev)) return; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; /* @@ -1531,19 +1551,18 @@ static void drm_legacy_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - unsigned long irqflags; /* vblank is not initialized (IRQ not installed ?), or has been freed */ - if (!dev->num_crtcs) + if (!drm_dev_has_vblank(dev)) return; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return; if (vblank->inmodeset) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); + spin_lock_irq(&dev->vbl_lock); drm_reset_vblank_timestamp(dev, pipe); - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + spin_unlock_irq(&dev->vbl_lock); if (vblank->inmodeset & 0x2) drm_vblank_put(dev, pipe); @@ -1559,7 +1578,7 @@ int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, unsigned int pipe; /* If drm_vblank_init() hasn't been called yet, just no-op */ - if (!dev->num_crtcs) + if (!drm_dev_has_vblank(dev)) return 0; /* KMS drivers handle this internally */ @@ -1584,11 +1603,6 @@ int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, return 0; } -static inline bool vblank_passed(u64 seq, u64 ref) -{ - return (seq - ref) <= (1 << 23); -} - static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, u64 req_seq, union drm_wait_vblank *vblwait, @@ -1597,7 +1611,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_pending_vblank_event *e; ktime_t now; - unsigned long flags; u64 seq; int ret; @@ -1614,11 +1627,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, e->event.vbl.crtc_id = 0; if (drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + if (crtc) e->event.vbl.crtc_id = crtc->base.id; } - spin_lock_irqsave(&dev->event_lock, flags); + spin_lock_irq(&dev->event_lock); /* * drm_crtc_vblank_off() might have been called after we called @@ -1639,13 +1653,13 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, seq = drm_vblank_count_and_time(dev, pipe, &now); - DRM_DEBUG("event on vblank count %llu, current %llu, crtc %u\n", - req_seq, seq, pipe); + drm_dbg_core(dev, "event on vblank count %llu, current %llu, crtc %u\n", + req_seq, seq, pipe); trace_drm_vblank_event_queued(file_priv, pipe, req_seq); e->sequence = req_seq; - if (vblank_passed(seq, req_seq)) { + if (drm_vblank_passed(seq, req_seq)) { drm_vblank_put(dev, pipe); send_vblank_event(dev, e, seq, now); vblwait->reply.sequence = seq; @@ -1655,12 +1669,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, vblwait->reply.sequence = req_seq; } - spin_unlock_irqrestore(&dev->event_lock, flags); + spin_unlock_irq(&dev->event_lock); return 0; err_unlock: - spin_unlock_irqrestore(&dev->event_lock, flags); + spin_unlock_irq(&dev->event_lock); kfree(e); err_put: drm_vblank_put(dev, pipe); @@ -1731,10 +1745,11 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, if (vblwait->request.type & ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | _DRM_VBLANK_HIGH_CRTC_MASK)) { - DRM_DEBUG("Unsupported type value 0x%x, supported mask 0x%x\n", - vblwait->request.type, - (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | - _DRM_VBLANK_HIGH_CRTC_MASK)); + drm_dbg_core(dev, + "Unsupported type value 0x%x, supported mask 0x%x\n", + vblwait->request.type, + (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | + _DRM_VBLANK_HIGH_CRTC_MASK)); return -EINVAL; } @@ -1777,7 +1792,9 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, ret = drm_vblank_get(dev, pipe); if (ret) { - DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); + drm_dbg_core(dev, + "crtc %d failed to acquire vblank counter, %d\n", + pipe, ret); return ret; } seq = drm_vblank_count(dev, pipe); @@ -1797,7 +1814,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, } if ((flags & _DRM_VBLANK_NEXTONMISS) && - vblank_passed(seq, req_seq)) { + drm_vblank_passed(seq, req_seq)) { req_seq = seq + 1; vblwait->request.type &= ~_DRM_VBLANK_NEXTONMISS; vblwait->request.sequence = req_seq; @@ -1813,10 +1830,10 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, if (req_seq != seq) { int wait; - DRM_DEBUG("waiting on vblank count %llu, crtc %u\n", - req_seq, pipe); + drm_dbg_core(dev, "waiting on vblank count %llu, crtc %u\n", + req_seq, pipe); wait = wait_event_interruptible_timeout(vblank->queue, - vblank_passed(drm_vblank_count(dev, pipe), req_seq) || + drm_vblank_passed(drm_vblank_count(dev, pipe), req_seq) || !READ_ONCE(vblank->enabled), msecs_to_jiffies(3000)); @@ -1838,10 +1855,11 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, if (ret != -EINTR) { drm_wait_vblank_reply(dev, pipe, &vblwait->reply); - DRM_DEBUG("crtc %d returning %u to client\n", - pipe, vblwait->reply.sequence); + drm_dbg_core(dev, "crtc %d returning %u to client\n", + pipe, vblwait->reply.sequence); } else { - DRM_DEBUG("crtc %d vblank wait interrupted by signal\n", pipe); + drm_dbg_core(dev, "crtc %d vblank wait interrupted by signal\n", + pipe); } done: @@ -1864,11 +1882,11 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != pipe) continue; - if (!vblank_passed(seq, e->sequence)) + if (!drm_vblank_passed(seq, e->sequence)) continue; - DRM_DEBUG("vblank event on %llu, current %llu\n", - e->sequence, seq); + drm_dbg_core(dev, "vblank event on %llu, current %llu\n", + e->sequence, seq); list_del(&e->base.link); drm_vblank_put(dev, pipe); @@ -1897,10 +1915,10 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) unsigned long irqflags; bool disable_irq; - if (WARN_ON_ONCE(!dev->num_crtcs)) + if (drm_WARN_ON_ONCE(dev, !drm_dev_has_vblank(dev))) return false; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) return false; spin_lock_irqsave(&dev->event_lock, irqflags); @@ -1934,6 +1952,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) !atomic_read(&vblank->refcount)); drm_handle_vblank_events(dev, pipe); + drm_handle_vblank_works(vblank); spin_unlock_irqrestore(&dev->event_lock, irqflags); @@ -2007,7 +2026,9 @@ int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, if (!vblank_enabled) { ret = drm_crtc_vblank_get(crtc); if (ret) { - DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); + drm_dbg_core(dev, + "crtc %d failed to acquire vblank counter, %d\n", + pipe, ret); return ret; } } @@ -2045,7 +2066,6 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, u64 seq; u64 req_seq; int ret; - unsigned long spin_flags; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; @@ -2073,7 +2093,9 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, ret = drm_crtc_vblank_get(crtc); if (ret) { - DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); + drm_dbg_core(dev, + "crtc %d failed to acquire vblank counter, %d\n", + pipe, ret); goto err_free; } @@ -2083,7 +2105,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, if (flags & DRM_CRTC_SEQUENCE_RELATIVE) req_seq += seq; - if ((flags & DRM_CRTC_SEQUENCE_NEXT_ON_MISS) && vblank_passed(seq, req_seq)) + if ((flags & DRM_CRTC_SEQUENCE_NEXT_ON_MISS) && drm_vblank_passed(seq, req_seq)) req_seq = seq + 1; e->pipe = pipe; @@ -2091,7 +2113,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, e->event.base.length = sizeof(e->event.seq); e->event.seq.user_data = queue_seq->user_data; - spin_lock_irqsave(&dev->event_lock, spin_flags); + spin_lock_irq(&dev->event_lock); /* * drm_crtc_vblank_off() might have been called after we called @@ -2112,7 +2134,7 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, e->sequence = req_seq; - if (vblank_passed(seq, req_seq)) { + if (drm_vblank_passed(seq, req_seq)) { drm_crtc_vblank_put(crtc); send_vblank_event(dev, e, seq, now); queue_seq->sequence = seq; @@ -2122,13 +2144,14 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, queue_seq->sequence = req_seq; } - spin_unlock_irqrestore(&dev->event_lock, spin_flags); + spin_unlock_irq(&dev->event_lock); return 0; err_unlock: - spin_unlock_irqrestore(&dev->event_lock, spin_flags); + spin_unlock_irq(&dev->event_lock); drm_crtc_vblank_put(crtc); err_free: kfree(e); return ret; } + |