From 23e16760863c3e898132f395027b352fb4d128b1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Tigeot?= Date: Sat, 8 Feb 2014 11:37:10 +0100 Subject: [PATCH] drm: Implement and use drm_send_vblank_event() --- sys/dev/drm/drm_irq.c | 79 +++++++++++++++++++++++++------- sys/dev/drm/i915/intel_display.c | 42 ++--------------- sys/dev/drm/include/drm/drmP.h | 7 ++- 3 files changed, 74 insertions(+), 54 deletions(-) diff --git a/sys/dev/drm/drm_irq.c b/sys/dev/drm/drm_irq.c index f5df28732e..817c95a3e6 100644 --- a/sys/dev/drm/drm_irq.c +++ b/sys/dev/drm/drm_irq.c @@ -31,6 +31,8 @@ * handing interrupt handlers off to the drivers. */ +#include +#include #include MALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data"); @@ -600,6 +602,15 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, return vbl_status; } +static struct timeval get_drm_timestamp(void) +{ + struct timeval now; + + getmicrouptime(&now); + + return now; +} + /** * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent * vblank interval. @@ -691,6 +702,50 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, return cur_vblank; } +static void send_vblank_event(struct drm_device *dev, + struct drm_pending_vblank_event *e, + unsigned long seq, struct timeval *now) +{ + KKASSERT(mutex_is_locked(&dev->event_lock)); + e->event.sequence = seq; + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_add_tail(&e->base.link, + &e->base.file_priv->event_list); + wakeup(&e->base.file_priv->event_list); +#if 0 + trace_drm_vblank_event_delivered(e->base.pid, e->pipe, + e->event.sequence); +#endif +} + +/** + * drm_send_vblank_event - helper to send vblank event after pageflip + * @dev: DRM device + * @crtc: CRTC in question + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + */ +void drm_send_vblank_event(struct drm_device *dev, int crtc, + struct drm_pending_vblank_event *e) +{ + struct timeval now; + unsigned int seq; + if (crtc >= 0) { + seq = drm_vblank_count_and_time(dev, crtc, &now); + } else { + seq = 0; + + now = get_drm_timestamp(); + } + e->pipe = crtc; + send_vblank_event(dev, e, seq, &now); +} +EXPORT_SYMBOL(drm_send_vblank_event); + /** * drm_update_vblank_count - update the master vblank counter * @dev: DRM device @@ -841,13 +896,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) DRM_DEBUG("Sending premature vblank event on disable: \ wanted %d, current %d\n", e->event.sequence, seq); - - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + list_del(&e->base.link); drm_vblank_put(dev, e->pipe); - list_move_tail(&e->base.link, &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); + send_vblank_event(dev, e, seq, &now); } lockmgr(&dev->event_lock, LK_RELEASE); @@ -989,12 +1040,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->event.sequence = vblwait->request.sequence; if ((seq - vblwait->request.sequence) <= (1 << 23)) { - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; drm_vblank_put(dev, pipe); - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); + send_vblank_event(dev, e, seq, &now); vblwait->reply.sequence = seq; } else { /* drm_handle_vblank_events will call drm_vblank_put */ @@ -1138,12 +1185,12 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) if ((seq - e->event.sequence) > (1<<23)) continue; - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + DRM_DEBUG("vblank event on %d, current %d\n", + e->event.sequence, seq); + + list_del(&e->base.link); drm_vblank_put(dev, e->pipe); - list_move_tail(&e->base.link, &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); + send_vblank_event(dev, e, seq, &now); } lockmgr(&dev->event_lock, LK_RELEASE); diff --git a/sys/dev/drm/i915/intel_display.c b/sys/dev/drm/i915/intel_display.c index d91e20dce7..784ff466f3 100644 --- a/sys/dev/drm/i915/intel_display.c +++ b/sys/dev/drm/i915/intel_display.c @@ -7282,15 +7282,11 @@ static void do_intel_finish_page_flip(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; struct drm_i915_gem_object *obj; - struct drm_pending_vblank_event *e; - struct timeval tnow, tvbl; /* Ignore early vblank irqs */ if (intel_crtc == NULL) return; - microtime(&tnow); - lockmgr(&dev->event_lock, LK_EXCLUSIVE); work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { @@ -7300,45 +7296,17 @@ static void do_intel_finish_page_flip(struct drm_device *dev, intel_crtc->unpin_work = NULL; - if (work->event) { - e = work->event; - e->event.sequence = drm_vblank_count_and_time(dev, intel_crtc->pipe, &tvbl); - - /* Called before vblank count and timestamps have - * been updated for the vblank interval of flip - * completion? Need to increment vblank count and - * add one videorefresh duration to returned timestamp - * to account for this. We assume this happened if we - * get called over 0.9 frame durations after the last - * timestamped vblank. - * - * This calculation can not be used with vrefresh rates - * below 5Hz (10Hz to be on the safe side) without - * promoting to 64 integers. - */ - if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) > - 9 * crtc->framedur_ns) { - e->event.sequence++; - tvbl = ns_to_timeval(timeval_to_ns(&tvbl) + - crtc->framedur_ns); - } - - e->event.tv_sec = tvbl.tv_sec; - e->event.tv_usec = tvbl.tv_usec; - - list_add_tail(&e->base.link, - &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); - } + if (work->event) + drm_send_vblank_event(dev, intel_crtc->pipe, work->event); drm_vblank_put(dev, intel_crtc->pipe); + lockmgr(&dev->event_lock, LK_RELEASE); + obj = work->old_fb_obj; atomic_clear_int(&obj->pending_flip, 1 << intel_crtc->plane); - if (atomic_load_acq_int(&obj->pending_flip) == 0) - wakeup(&obj->pending_flip); - lockmgr(&dev->event_lock, LK_RELEASE); + wakeup(&obj->pending_flip); taskqueue_enqueue(dev_priv->tq, &work->task); } diff --git a/sys/dev/drm/include/drm/drmP.h b/sys/dev/drm/include/drm/drmP.h index e206958101..d8dbe80fd2 100644 --- a/sys/dev/drm/include/drm/drmP.h +++ b/sys/dev/drm/include/drm/drmP.h @@ -148,6 +148,9 @@ struct drm_device; #define DRIVER_PRIME 0x4000 #define DRIVER_LOCKLESS_IRQ 0x8000 +/***********************************************************************/ +/** \name Begin the DRM... */ +/*@{*/ #define DRM_HASH_SIZE 16 /* Size of key hash table */ #define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ @@ -1206,7 +1209,7 @@ void drm_free_buffer(struct drm_device *dev, drm_buf_t *buf); void drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv); #define drm_core_reclaim_buffers drm_reclaim_buffers -/* IRQ support (drm_irq.c) */ + /* IRQ support (drm_irq.h) */ int drm_irq_install(struct drm_device *dev); int drm_irq_uninstall(struct drm_device *dev); irqreturn_t drm_irq_handler(DRM_IRQ_ARGS); @@ -1226,6 +1229,8 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime); +extern void drm_send_vblank_event(struct drm_device *dev, int crtc, + struct drm_pending_vblank_event *e); extern bool drm_handle_vblank(struct drm_device *dev, int crtc); void drm_handle_vblank_events(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); -- 2.41.0