1280183Sdumbbell/** 2280183Sdumbbell * \file drm_irq.c 3280183Sdumbbell * IRQ support 4280183Sdumbbell * 5280183Sdumbbell * \author Rickard E. (Rik) Faith <faith@valinux.com> 6280183Sdumbbell * \author Gareth Hughes <gareth@valinux.com> 7280183Sdumbbell */ 8280183Sdumbbell 9280183Sdumbbell/* 10280183Sdumbbell * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com 11280183Sdumbbell * 12280183Sdumbbell * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 13280183Sdumbbell * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 14235783Skib * All Rights Reserved. 15235783Skib * 16235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 17235783Skib * copy of this software and associated documentation files (the "Software"), 18235783Skib * to deal in the Software without restriction, including without limitation 19235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20235783Skib * and/or sell copies of the Software, and to permit persons to whom the 21235783Skib * Software is furnished to do so, subject to the following conditions: 22235783Skib * 23235783Skib * The above copyright notice and this permission notice (including the next 24235783Skib * paragraph) shall be included in all copies or substantial portions of the 25235783Skib * Software. 26235783Skib * 27235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30280183Sdumbbell * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31280183Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32280183Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33280183Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 34235783Skib */ 35235783Skib 36235783Skib#include <sys/cdefs.h> 37235783Skib__FBSDID("$FreeBSD$"); 38235783Skib 39235783Skib#include <dev/drm2/drmP.h> 40235783Skib 41235783Skib/* Access macro for slots in vblank timestamp ringbuffer. */ 42235783Skib#define vblanktimestamp(dev, crtc, count) ( \ 43235783Skib (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \ 44235783Skib ((count) % DRM_VBLANKTIME_RBSIZE)]) 45235783Skib 46235783Skib/* Retry timestamp calculation up to 3 times to satisfy 47235783Skib * drm_timestamp_precision before giving up. 48235783Skib */ 49235783Skib#define DRM_TIMESTAMP_MAXRETRIES 3 50235783Skib 51235783Skib/* Threshold in nanoseconds for detection of redundant 52235783Skib * vblank irq in drm_handle_vblank(). 1 msec should be ok. 53235783Skib */ 54235783Skib#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 55235783Skib 56280183Sdumbbell/** 57280183Sdumbbell * Get interrupt from bus id. 58280183Sdumbbell * 59280183Sdumbbell * \param inode device inode. 60280183Sdumbbell * \param file_priv DRM file private. 61280183Sdumbbell * \param cmd command. 62280183Sdumbbell * \param arg user argument, pointing to a drm_irq_busid structure. 63280183Sdumbbell * \return zero on success or a negative number on failure. 64280183Sdumbbell * 65280183Sdumbbell * Finds the PCI device with the specified bus id and gets its IRQ number. 66280183Sdumbbell * This IOCTL is deprecated, and will now return EINVAL for any busid not equal 67280183Sdumbbell * to that of the device that this DRM instance attached to. 68280183Sdumbbell */ 69235783Skibint drm_irq_by_busid(struct drm_device *dev, void *data, 70235783Skib struct drm_file *file_priv) 71235783Skib{ 72280183Sdumbbell struct drm_irq_busid *p = data; 73235783Skib 74280183Sdumbbell if (!dev->driver->bus->irq_by_busid) 75280183Sdumbbell return -EINVAL; 76235783Skib 77280183Sdumbbell if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 78280183Sdumbbell return -EINVAL; 79235783Skib 80280183Sdumbbell return dev->driver->bus->irq_by_busid(dev, p); 81235783Skib} 82235783Skib 83235783Skib/* 84235783Skib * Clear vblank timestamp buffer for a crtc. 85235783Skib */ 86235783Skibstatic void clear_vblank_timestamps(struct drm_device *dev, int crtc) 87235783Skib{ 88235783Skib memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0, 89235783Skib DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval)); 90235783Skib} 91235783Skib 92235783Skib/* 93235783Skib * Disable vblank irq's on crtc, make sure that last vblank count 94235783Skib * of hardware and corresponding consistent software vblank counter 95235783Skib * are preserved, even if there are any spurious vblank irq's after 96235783Skib * disable. 97235783Skib */ 98235783Skibstatic void vblank_disable_and_save(struct drm_device *dev, int crtc) 99235783Skib{ 100235783Skib u32 vblcount; 101280183Sdumbbell s64 diff_ns; 102235783Skib int vblrc; 103235783Skib struct timeval tvblank; 104280183Sdumbbell int count = DRM_TIMESTAMP_MAXRETRIES; 105235783Skib 106235783Skib /* Prevent vblank irq processing while disabling vblank irqs, 107235783Skib * so no updates of timestamps or count can happen after we've 108235783Skib * disabled. Needed to prevent races in case of delayed irq's. 109235783Skib */ 110235783Skib mtx_lock(&dev->vblank_time_lock); 111235783Skib 112235783Skib dev->driver->disable_vblank(dev, crtc); 113235783Skib dev->vblank_enabled[crtc] = 0; 114235783Skib 115235783Skib /* No further vblank irq's will be processed after 116235783Skib * this point. Get current hardware vblank count and 117235783Skib * vblank timestamp, repeat until they are consistent. 118235783Skib * 119235783Skib * FIXME: There is still a race condition here and in 120235783Skib * drm_update_vblank_count() which can cause off-by-one 121235783Skib * reinitialization of software vblank counter. If gpu 122235783Skib * vblank counter doesn't increment exactly at the leading 123235783Skib * edge of a vblank interval, then we can lose 1 count if 124235783Skib * we happen to execute between start of vblank and the 125235783Skib * delayed gpu counter increment. 126235783Skib */ 127235783Skib do { 128235783Skib dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); 129235783Skib vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); 130280183Sdumbbell } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); 131235783Skib 132280183Sdumbbell if (!count) 133280183Sdumbbell vblrc = 0; 134280183Sdumbbell 135235783Skib /* Compute time difference to stored timestamp of last vblank 136235783Skib * as updated by last invocation of drm_handle_vblank() in vblank irq. 137235783Skib */ 138235783Skib vblcount = atomic_read(&dev->_vblank_count[crtc]); 139235783Skib diff_ns = timeval_to_ns(&tvblank) - 140235783Skib timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); 141235783Skib 142235783Skib /* If there is at least 1 msec difference between the last stored 143235783Skib * timestamp and tvblank, then we are currently executing our 144235783Skib * disable inside a new vblank interval, the tvblank timestamp 145235783Skib * corresponds to this new vblank interval and the irq handler 146235783Skib * for this vblank didn't run yet and won't run due to our disable. 147235783Skib * Therefore we need to do the job of drm_handle_vblank() and 148235783Skib * increment the vblank counter by one to account for this vblank. 149235783Skib * 150235783Skib * Skip this step if there isn't any high precision timestamp 151235783Skib * available. In that case we can't account for this and just 152235783Skib * hope for the best. 153235783Skib */ 154235783Skib if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { 155235783Skib atomic_inc(&dev->_vblank_count[crtc]); 156280183Sdumbbell smp_mb__after_atomic_inc(); 157235783Skib } 158235783Skib 159235783Skib /* Invalidate all timestamps while vblank irq's are off. */ 160235783Skib clear_vblank_timestamps(dev, crtc); 161235783Skib 162235783Skib mtx_unlock(&dev->vblank_time_lock); 163235783Skib} 164235783Skib 165280183Sdumbbellstatic void vblank_disable_fn(void *arg) 166235783Skib{ 167235783Skib struct drm_device *dev = (struct drm_device *)arg; 168235783Skib int i; 169235783Skib 170235783Skib if (!dev->vblank_disable_allowed) 171235783Skib return; 172235783Skib 173235783Skib for (i = 0; i < dev->num_crtcs; i++) { 174235783Skib mtx_lock(&dev->vbl_lock); 175235783Skib if (atomic_read(&dev->vblank_refcount[i]) == 0 && 176235783Skib dev->vblank_enabled[i]) { 177235783Skib DRM_DEBUG("disabling vblank on crtc %d\n", i); 178235783Skib vblank_disable_and_save(dev, i); 179235783Skib } 180235783Skib mtx_unlock(&dev->vbl_lock); 181235783Skib } 182235783Skib} 183235783Skib 184235783Skibvoid drm_vblank_cleanup(struct drm_device *dev) 185235783Skib{ 186235783Skib /* Bail if the driver didn't call drm_vblank_init() */ 187235783Skib if (dev->num_crtcs == 0) 188235783Skib return; 189235783Skib 190235783Skib callout_stop(&dev->vblank_disable_callout); 191235783Skib 192235783Skib vblank_disable_fn(dev); 193235783Skib 194235783Skib free(dev->_vblank_count, DRM_MEM_VBLANK); 195235783Skib free(dev->vblank_refcount, DRM_MEM_VBLANK); 196235783Skib free(dev->vblank_enabled, DRM_MEM_VBLANK); 197235783Skib free(dev->last_vblank, DRM_MEM_VBLANK); 198235783Skib free(dev->last_vblank_wait, DRM_MEM_VBLANK); 199235783Skib free(dev->vblank_inmodeset, DRM_MEM_VBLANK); 200235783Skib free(dev->_vblank_time, DRM_MEM_VBLANK); 201235783Skib 202280183Sdumbbell mtx_destroy(&dev->vbl_lock); 203280183Sdumbbell mtx_destroy(&dev->vblank_time_lock); 204280183Sdumbbell 205235783Skib dev->num_crtcs = 0; 206235783Skib} 207280183SdumbbellEXPORT_SYMBOL(drm_vblank_cleanup); 208235783Skib 209235783Skibint drm_vblank_init(struct drm_device *dev, int num_crtcs) 210235783Skib{ 211280183Sdumbbell int i, ret = -ENOMEM; 212235783Skib 213283291Sjkim callout_init(&dev->vblank_disable_callout, 1); 214235783Skib mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); 215235783Skib mtx_init(&dev->vblank_time_lock, "drmvtl", NULL, MTX_DEF); 216235783Skib 217235783Skib dev->num_crtcs = num_crtcs; 218235783Skib 219235783Skib dev->_vblank_count = malloc(sizeof(atomic_t) * num_crtcs, 220280183Sdumbbell DRM_MEM_VBLANK, M_NOWAIT); 221280183Sdumbbell if (!dev->_vblank_count) 222280183Sdumbbell goto err; 223280183Sdumbbell 224235783Skib dev->vblank_refcount = malloc(sizeof(atomic_t) * num_crtcs, 225280183Sdumbbell DRM_MEM_VBLANK, M_NOWAIT); 226280183Sdumbbell if (!dev->vblank_refcount) 227280183Sdumbbell goto err; 228280183Sdumbbell 229235783Skib dev->vblank_enabled = malloc(num_crtcs * sizeof(int), 230280183Sdumbbell DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); 231280183Sdumbbell if (!dev->vblank_enabled) 232280183Sdumbbell goto err; 233280183Sdumbbell 234235783Skib dev->last_vblank = malloc(num_crtcs * sizeof(u32), 235280183Sdumbbell DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); 236280183Sdumbbell if (!dev->last_vblank) 237280183Sdumbbell goto err; 238280183Sdumbbell 239235783Skib dev->last_vblank_wait = malloc(num_crtcs * sizeof(u32), 240280183Sdumbbell DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); 241280183Sdumbbell if (!dev->last_vblank_wait) 242280183Sdumbbell goto err; 243280183Sdumbbell 244235783Skib dev->vblank_inmodeset = malloc(num_crtcs * sizeof(int), 245280183Sdumbbell DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); 246280183Sdumbbell if (!dev->vblank_inmodeset) 247280183Sdumbbell goto err; 248280183Sdumbbell 249235783Skib dev->_vblank_time = malloc(num_crtcs * DRM_VBLANKTIME_RBSIZE * 250280183Sdumbbell sizeof(struct timeval), DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); 251280183Sdumbbell if (!dev->_vblank_time) 252280183Sdumbbell goto err; 253280183Sdumbbell 254235783Skib DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n"); 255235783Skib 256235783Skib /* Driver specific high-precision vblank timestamping supported? */ 257235783Skib if (dev->driver->get_vblank_timestamp) 258235783Skib DRM_INFO("Driver supports precise vblank timestamp query.\n"); 259235783Skib else 260235783Skib DRM_INFO("No driver support for vblank timestamp query.\n"); 261235783Skib 262235783Skib /* Zero per-crtc vblank stuff */ 263235783Skib for (i = 0; i < num_crtcs; i++) { 264235783Skib atomic_set(&dev->_vblank_count[i], 0); 265235783Skib atomic_set(&dev->vblank_refcount[i], 0); 266235783Skib } 267235783Skib 268235783Skib dev->vblank_disable_allowed = 0; 269235783Skib return 0; 270280183Sdumbbell 271280183Sdumbbellerr: 272280183Sdumbbell drm_vblank_cleanup(dev); 273280183Sdumbbell return ret; 274235783Skib} 275280183SdumbbellEXPORT_SYMBOL(drm_vblank_init); 276235783Skib 277280183Sdumbbell/** 278280183Sdumbbell * Install IRQ handler. 279280183Sdumbbell * 280280183Sdumbbell * \param dev DRM device. 281280183Sdumbbell * 282280183Sdumbbell * Initializes the IRQ related data. Installs the handler, calling the driver 283280183Sdumbbell * \c irq_preinstall() and \c irq_postinstall() functions 284280183Sdumbbell * before and after the installation. 285280183Sdumbbell */ 286280183Sdumbbellint drm_irq_install(struct drm_device *dev) 287235783Skib{ 288280183Sdumbbell int ret; 289280183Sdumbbell unsigned long sh_flags = 0; 290235783Skib 291280183Sdumbbell if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 292280183Sdumbbell return -EINVAL; 293280183Sdumbbell 294280183Sdumbbell if (drm_dev_to_irq(dev) == 0) 295280183Sdumbbell return -EINVAL; 296280183Sdumbbell 297280183Sdumbbell DRM_LOCK(dev); 298280183Sdumbbell 299280183Sdumbbell /* Driver must have been initialized */ 300280183Sdumbbell if (!dev->dev_private) { 301280183Sdumbbell DRM_UNLOCK(dev); 302280183Sdumbbell return -EINVAL; 303280183Sdumbbell } 304280183Sdumbbell 305280183Sdumbbell if (dev->irq_enabled) { 306280183Sdumbbell DRM_UNLOCK(dev); 307280183Sdumbbell return -EBUSY; 308280183Sdumbbell } 309280183Sdumbbell dev->irq_enabled = 1; 310280183Sdumbbell DRM_UNLOCK(dev); 311280183Sdumbbell 312280183Sdumbbell DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); 313280183Sdumbbell 314280183Sdumbbell /* Before installing handler */ 315280183Sdumbbell if (dev->driver->irq_preinstall) 316280183Sdumbbell dev->driver->irq_preinstall(dev); 317280183Sdumbbell 318280183Sdumbbell /* Install handler */ 319280183Sdumbbell sh_flags = INTR_TYPE_TTY | INTR_MPSAFE; 320280183Sdumbbell if (!drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) 321280183Sdumbbell /* 322280183Sdumbbell * FIXME Linux<->FreeBSD: This seems to make 323280183Sdumbbell * bus_setup_intr() unhappy: it was reported to return 324280183Sdumbbell * EINVAL on an i915 board (8086:2592 in a Thinkpad 325280183Sdumbbell * X41). 326280183Sdumbbell * 327280183Sdumbbell * For now, no driver we have use that. 328280183Sdumbbell */ 329280183Sdumbbell sh_flags |= INTR_EXCL; 330280183Sdumbbell 331280183Sdumbbell ret = -bus_setup_intr(dev->dev, dev->irqr, sh_flags, NULL, 332280183Sdumbbell dev->driver->irq_handler, dev, &dev->irqh); 333280183Sdumbbell 334280183Sdumbbell if (ret < 0) { 335280183Sdumbbell device_printf(dev->dev, "Error setting interrupt: %d\n", -ret); 336280183Sdumbbell DRM_LOCK(dev); 337280183Sdumbbell dev->irq_enabled = 0; 338280183Sdumbbell DRM_UNLOCK(dev); 339280183Sdumbbell return ret; 340280183Sdumbbell } 341280183Sdumbbell 342280183Sdumbbell /* After installing handler */ 343280183Sdumbbell if (dev->driver->irq_postinstall) 344280183Sdumbbell ret = dev->driver->irq_postinstall(dev); 345280183Sdumbbell 346280183Sdumbbell if (ret < 0) { 347280183Sdumbbell DRM_LOCK(dev); 348280183Sdumbbell dev->irq_enabled = 0; 349280183Sdumbbell DRM_UNLOCK(dev); 350280183Sdumbbell bus_teardown_intr(dev->dev, dev->irqr, dev->irqh); 351280183Sdumbbell dev->driver->bus->free_irq(dev); 352280183Sdumbbell } 353280183Sdumbbell 354280183Sdumbbell return ret; 355280183Sdumbbell} 356280183SdumbbellEXPORT_SYMBOL(drm_irq_install); 357280183Sdumbbell 358280183Sdumbbell/** 359280183Sdumbbell * Uninstall the IRQ handler. 360280183Sdumbbell * 361280183Sdumbbell * \param dev DRM device. 362280183Sdumbbell * 363280183Sdumbbell * Calls the driver's \c irq_uninstall() function, and stops the irq. 364280183Sdumbbell */ 365280183Sdumbbellint drm_irq_uninstall(struct drm_device *dev) 366280183Sdumbbell{ 367280183Sdumbbell int irq_enabled, i; 368280183Sdumbbell 369280183Sdumbbell if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 370280183Sdumbbell return -EINVAL; 371280183Sdumbbell 372280183Sdumbbell DRM_LOCK(dev); 373280183Sdumbbell irq_enabled = dev->irq_enabled; 374280183Sdumbbell dev->irq_enabled = 0; 375280183Sdumbbell DRM_UNLOCK(dev); 376280183Sdumbbell 377280183Sdumbbell /* 378280183Sdumbbell * Wake up any waiters so they don't hang. 379280183Sdumbbell */ 380280183Sdumbbell if (dev->num_crtcs) { 381280183Sdumbbell mtx_lock(&dev->vbl_lock); 382280183Sdumbbell for (i = 0; i < dev->num_crtcs; i++) { 383280183Sdumbbell DRM_WAKEUP(&dev->_vblank_count[i]); 384280183Sdumbbell dev->vblank_enabled[i] = 0; 385280183Sdumbbell dev->last_vblank[i] = 386280183Sdumbbell dev->driver->get_vblank_counter(dev, i); 387280183Sdumbbell } 388280183Sdumbbell mtx_unlock(&dev->vbl_lock); 389280183Sdumbbell } 390280183Sdumbbell 391280183Sdumbbell if (!irq_enabled) 392280183Sdumbbell return -EINVAL; 393280183Sdumbbell 394280183Sdumbbell DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); 395280183Sdumbbell 396280183Sdumbbell if (dev->driver->irq_uninstall) 397280183Sdumbbell dev->driver->irq_uninstall(dev); 398280183Sdumbbell 399280183Sdumbbell bus_teardown_intr(dev->dev, dev->irqr, dev->irqh); 400280183Sdumbbell dev->driver->bus->free_irq(dev); 401280183Sdumbbell 402280183Sdumbbell return 0; 403280183Sdumbbell} 404280183SdumbbellEXPORT_SYMBOL(drm_irq_uninstall); 405280183Sdumbbell 406280183Sdumbbell/** 407280183Sdumbbell * IRQ control ioctl. 408280183Sdumbbell * 409280183Sdumbbell * \param inode device inode. 410280183Sdumbbell * \param file_priv DRM file private. 411280183Sdumbbell * \param cmd command. 412280183Sdumbbell * \param arg user argument, pointing to a drm_control structure. 413280183Sdumbbell * \return zero on success or a negative number on failure. 414280183Sdumbbell * 415280183Sdumbbell * Calls irq_install() or irq_uninstall() according to \p arg. 416280183Sdumbbell */ 417280183Sdumbbellint drm_control(struct drm_device *dev, void *data, 418280183Sdumbbell struct drm_file *file_priv) 419280183Sdumbbell{ 420280183Sdumbbell struct drm_control *ctl = data; 421280183Sdumbbell 422280183Sdumbbell /* if we haven't irq we fallback for compatibility reasons - 423280183Sdumbbell * this used to be a separate function in drm_dma.h 424280183Sdumbbell */ 425280183Sdumbbell 426280183Sdumbbell 427280183Sdumbbell switch (ctl->func) { 428280183Sdumbbell case DRM_INST_HANDLER: 429280183Sdumbbell if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 430280183Sdumbbell return 0; 431280183Sdumbbell if (drm_core_check_feature(dev, DRIVER_MODESET)) 432280183Sdumbbell return 0; 433280183Sdumbbell if (dev->if_version < DRM_IF_VERSION(1, 2) && 434280183Sdumbbell ctl->irq != drm_dev_to_irq(dev)) 435280183Sdumbbell return -EINVAL; 436280183Sdumbbell return drm_irq_install(dev); 437280183Sdumbbell case DRM_UNINST_HANDLER: 438280183Sdumbbell if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 439280183Sdumbbell return 0; 440280183Sdumbbell if (drm_core_check_feature(dev, DRIVER_MODESET)) 441280183Sdumbbell return 0; 442280183Sdumbbell return drm_irq_uninstall(dev); 443280183Sdumbbell default: 444280183Sdumbbell return -EINVAL; 445280183Sdumbbell } 446280183Sdumbbell} 447280183Sdumbbell 448280183Sdumbbell/** 449280183Sdumbbell * drm_calc_timestamping_constants - Calculate and 450280183Sdumbbell * store various constants which are later needed by 451280183Sdumbbell * vblank and swap-completion timestamping, e.g, by 452280183Sdumbbell * drm_calc_vbltimestamp_from_scanoutpos(). 453280183Sdumbbell * They are derived from crtc's true scanout timing, 454280183Sdumbbell * so they take things like panel scaling or other 455280183Sdumbbell * adjustments into account. 456280183Sdumbbell * 457280183Sdumbbell * @crtc drm_crtc whose timestamp constants should be updated. 458280183Sdumbbell * 459280183Sdumbbell */ 460280183Sdumbbellvoid drm_calc_timestamping_constants(struct drm_crtc *crtc) 461280183Sdumbbell{ 462280183Sdumbbell s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; 463280183Sdumbbell u64 dotclock; 464280183Sdumbbell 465235783Skib /* Dot clock in Hz: */ 466280183Sdumbbell dotclock = (u64) crtc->hwmode.clock * 1000; 467235783Skib 468235783Skib /* Fields of interlaced scanout modes are only halve a frame duration. 469235783Skib * Double the dotclock to get halve the frame-/line-/pixelduration. 470235783Skib */ 471235783Skib if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE) 472235783Skib dotclock *= 2; 473235783Skib 474235783Skib /* Valid dotclock? */ 475235783Skib if (dotclock > 0) { 476235783Skib /* Convert scanline length in pixels and video dot clock to 477235783Skib * line duration, frame duration and pixel duration in 478235783Skib * nanoseconds: 479235783Skib */ 480280183Sdumbbell pixeldur_ns = (s64) div64_u64(1000000000, dotclock); 481280183Sdumbbell linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * 482280183Sdumbbell 1000000000), dotclock); 483280183Sdumbbell framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns; 484235783Skib } else 485235783Skib DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", 486235783Skib crtc->base.id); 487235783Skib 488235783Skib crtc->pixeldur_ns = pixeldur_ns; 489235783Skib crtc->linedur_ns = linedur_ns; 490235783Skib crtc->framedur_ns = framedur_ns; 491235783Skib 492235783Skib DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", 493235783Skib crtc->base.id, crtc->hwmode.crtc_htotal, 494235783Skib crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); 495235783Skib DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", 496235783Skib crtc->base.id, (int) dotclock/1000, (int) framedur_ns, 497235783Skib (int) linedur_ns, (int) pixeldur_ns); 498235783Skib} 499280183SdumbbellEXPORT_SYMBOL(drm_calc_timestamping_constants); 500235783Skib 501235783Skib/** 502235783Skib * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms 503235783Skib * drivers. Implements calculation of exact vblank timestamps from 504235783Skib * given drm_display_mode timings and current video scanout position 505235783Skib * of a crtc. This can be called from within get_vblank_timestamp() 506235783Skib * implementation of a kms driver to implement the actual timestamping. 507235783Skib * 508235783Skib * Should return timestamps conforming to the OML_sync_control OpenML 509235783Skib * extension specification. The timestamp corresponds to the end of 510235783Skib * the vblank interval, aka start of scanout of topmost-leftmost display 511235783Skib * pixel in the following video frame. 512235783Skib * 513235783Skib * Requires support for optional dev->driver->get_scanout_position() 514235783Skib * in kms driver, plus a bit of setup code to provide a drm_display_mode 515235783Skib * that corresponds to the true scanout timing. 516235783Skib * 517235783Skib * The current implementation only handles standard video modes. It 518235783Skib * returns as no operation if a doublescan or interlaced video mode is 519235783Skib * active. Higher level code is expected to handle this. 520235783Skib * 521235783Skib * @dev: DRM device. 522235783Skib * @crtc: Which crtc's vblank timestamp to retrieve. 523235783Skib * @max_error: Desired maximum allowable error in timestamps (nanosecs). 524235783Skib * On return contains true maximum error of timestamp. 525235783Skib * @vblank_time: Pointer to struct timeval which should receive the timestamp. 526235783Skib * @flags: Flags to pass to driver: 527235783Skib * 0 = Default. 528235783Skib * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. 529235783Skib * @refcrtc: drm_crtc* of crtc which defines scanout timing. 530235783Skib * 531235783Skib * Returns negative value on error, failure or if not supported in current 532235783Skib * video mode: 533235783Skib * 534235783Skib * -EINVAL - Invalid crtc. 535235783Skib * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. 536235783Skib * -ENOTSUPP - Function not supported in current display mode. 537235783Skib * -EIO - Failed, e.g., due to failed scanout position query. 538235783Skib * 539235783Skib * Returns or'ed positive status flags on success: 540235783Skib * 541235783Skib * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. 542235783Skib * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. 543235783Skib * 544235783Skib */ 545280183Sdumbbellint drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, 546280183Sdumbbell int *max_error, 547280183Sdumbbell struct timeval *vblank_time, 548280183Sdumbbell unsigned flags, 549280183Sdumbbell struct drm_crtc *refcrtc) 550235783Skib{ 551235783Skib struct timeval stime, raw_time; 552235783Skib struct drm_display_mode *mode; 553235783Skib int vbl_status, vtotal, vdisplay; 554235783Skib int vpos, hpos, i; 555280183Sdumbbell s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; 556235783Skib bool invbl; 557235783Skib 558235783Skib if (crtc < 0 || crtc >= dev->num_crtcs) { 559235783Skib DRM_ERROR("Invalid crtc %d\n", crtc); 560235783Skib return -EINVAL; 561235783Skib } 562235783Skib 563235783Skib /* Scanout position query not supported? Should not happen. */ 564235783Skib if (!dev->driver->get_scanout_position) { 565235783Skib DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); 566235783Skib return -EIO; 567235783Skib } 568235783Skib 569235783Skib mode = &refcrtc->hwmode; 570235783Skib vtotal = mode->crtc_vtotal; 571235783Skib vdisplay = mode->crtc_vdisplay; 572235783Skib 573235783Skib /* Durations of frames, lines, pixels in nanoseconds. */ 574235783Skib framedur_ns = refcrtc->framedur_ns; 575235783Skib linedur_ns = refcrtc->linedur_ns; 576235783Skib pixeldur_ns = refcrtc->pixeldur_ns; 577235783Skib 578235783Skib /* If mode timing undefined, just return as no-op: 579235783Skib * Happens during initial modesetting of a crtc. 580235783Skib */ 581235783Skib if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { 582235783Skib DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); 583235783Skib return -EAGAIN; 584235783Skib } 585235783Skib 586235783Skib /* Get current scanout position with system timestamp. 587235783Skib * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times 588235783Skib * if single query takes longer than max_error nanoseconds. 589235783Skib * 590235783Skib * This guarantees a tight bound on maximum error if 591235783Skib * code gets preempted or delayed for some reason. 592235783Skib */ 593235783Skib for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { 594235783Skib /* Disable preemption to make it very likely to 595280183Sdumbbell * succeed in the first iteration even on PREEMPT_RT kernel. 596235783Skib */ 597235783Skib critical_enter(); 598235783Skib 599235783Skib /* Get system timestamp before query. */ 600235783Skib getmicrouptime(&stime); 601235783Skib 602235783Skib /* Get vertical and horizontal scanout pos. vpos, hpos. */ 603235783Skib vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos); 604235783Skib 605235783Skib /* Get system timestamp after query. */ 606235783Skib getmicrouptime(&raw_time); 607280183Sdumbbell#ifdef FREEBSD_NOTYET 608280183Sdumbbell if (!drm_timestamp_monotonic) 609280183Sdumbbell mono_time_offset = ktime_get_monotonic_offset(); 610280183Sdumbbell#endif /* FREEBSD_NOTYET */ 611235783Skib 612235783Skib critical_exit(); 613235783Skib 614235783Skib /* Return as no-op if scanout query unsupported or failed. */ 615235783Skib if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { 616235783Skib DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", 617235783Skib crtc, vbl_status); 618235783Skib return -EIO; 619235783Skib } 620235783Skib 621235783Skib duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime); 622235783Skib 623235783Skib /* Accept result with < max_error nsecs timing uncertainty. */ 624280183Sdumbbell if (duration_ns <= (s64) *max_error) 625235783Skib break; 626235783Skib } 627235783Skib 628235783Skib /* Noisy system timing? */ 629235783Skib if (i == DRM_TIMESTAMP_MAXRETRIES) { 630235783Skib DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", 631235783Skib crtc, (int) duration_ns/1000, *max_error/1000, i); 632235783Skib } 633235783Skib 634235783Skib /* Return upper bound of timestamp precision error. */ 635235783Skib *max_error = (int) duration_ns; 636235783Skib 637235783Skib /* Check if in vblank area: 638235783Skib * vpos is >=0 in video scanout area, but negative 639235783Skib * within vblank area, counting down the number of lines until 640235783Skib * start of scanout. 641235783Skib */ 642235783Skib invbl = vbl_status & DRM_SCANOUTPOS_INVBL; 643235783Skib 644235783Skib /* Convert scanout position into elapsed time at raw_time query 645235783Skib * since start of scanout at first display scanline. delta_ns 646235783Skib * can be negative if start of scanout hasn't happened yet. 647235783Skib */ 648280183Sdumbbell delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; 649235783Skib 650235783Skib /* Is vpos outside nominal vblank area, but less than 651235783Skib * 1/100 of a frame height away from start of vblank? 652235783Skib * If so, assume this isn't a massively delayed vblank 653235783Skib * interrupt, but a vblank interrupt that fired a few 654235783Skib * microseconds before true start of vblank. Compensate 655235783Skib * by adding a full frame duration to the final timestamp. 656235783Skib * Happens, e.g., on ATI R500, R600. 657235783Skib * 658235783Skib * We only do this if DRM_CALLED_FROM_VBLIRQ. 659235783Skib */ 660235783Skib if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && 661235783Skib ((vdisplay - vpos) < vtotal / 100)) { 662235783Skib delta_ns = delta_ns - framedur_ns; 663235783Skib 664235783Skib /* Signal this correction as "applied". */ 665235783Skib vbl_status |= 0x8; 666235783Skib } 667235783Skib 668280183Sdumbbell#ifdef FREEBSD_NOTYET 669280183Sdumbbell if (!drm_timestamp_monotonic) 670280183Sdumbbell etime = ktime_sub(etime, mono_time_offset); 671280183Sdumbbell 672280183Sdumbbell /* save this only for debugging purposes */ 673280183Sdumbbell tv_etime = ktime_to_timeval(etime); 674280183Sdumbbell#endif /* FREEBSD_NOTYET */ 675235783Skib /* Subtract time delta from raw timestamp to get final 676235783Skib * vblank_time timestamp for end of vblank. 677235783Skib */ 678235783Skib *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns); 679235783Skib 680235783Skib DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %jd.%jd -> %jd.%jd [e %d us, %d rep]\n", 681235783Skib crtc, (int)vbl_status, hpos, vpos, (uintmax_t)raw_time.tv_sec, 682235783Skib (uintmax_t)raw_time.tv_usec, (uintmax_t)vblank_time->tv_sec, 683235783Skib (uintmax_t)vblank_time->tv_usec, (int)duration_ns/1000, i); 684235783Skib 685235783Skib vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; 686235783Skib if (invbl) 687235783Skib vbl_status |= DRM_VBLANKTIME_INVBL; 688235783Skib 689235783Skib return vbl_status; 690235783Skib} 691280183SdumbbellEXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); 692235783Skib 693280183Sdumbbellstatic struct timeval get_drm_timestamp(void) 694280183Sdumbbell{ 695280183Sdumbbell struct timeval now; 696280183Sdumbbell 697280183Sdumbbell microtime(&now); 698280183Sdumbbell#ifdef FREEBSD_NOTYET 699280183Sdumbbell if (!drm_timestamp_monotonic) 700280183Sdumbbell now = ktime_sub(now, ktime_get_monotonic_offset()); 701280183Sdumbbell#endif /* defined(FREEBSD_NOTYET) */ 702280183Sdumbbell 703280183Sdumbbell return now; 704280183Sdumbbell} 705280183Sdumbbell 706235783Skib/** 707235783Skib * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent 708235783Skib * vblank interval. 709235783Skib * 710235783Skib * @dev: DRM device 711235783Skib * @crtc: which crtc's vblank timestamp to retrieve 712235783Skib * @tvblank: Pointer to target struct timeval which should receive the timestamp 713235783Skib * @flags: Flags to pass to driver: 714235783Skib * 0 = Default. 715235783Skib * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. 716235783Skib * 717235783Skib * Fetches the system timestamp corresponding to the time of the most recent 718235783Skib * vblank interval on specified crtc. May call into kms-driver to 719235783Skib * compute the timestamp with a high-precision GPU specific method. 720235783Skib * 721235783Skib * Returns zero if timestamp originates from uncorrected do_gettimeofday() 722235783Skib * call, i.e., it isn't very precisely locked to the true vblank. 723235783Skib * 724235783Skib * Returns non-zero if timestamp is considered to be very precise. 725235783Skib */ 726235783Skibu32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, 727235783Skib struct timeval *tvblank, unsigned flags) 728235783Skib{ 729277487Skib int ret; 730235783Skib 731235783Skib /* Define requested maximum error on timestamps (nanoseconds). */ 732235783Skib int max_error = (int) drm_timestamp_precision * 1000; 733235783Skib 734235783Skib /* Query driver if possible and precision timestamping enabled. */ 735235783Skib if (dev->driver->get_vblank_timestamp && (max_error > 0)) { 736235783Skib ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, 737235783Skib tvblank, flags); 738235783Skib if (ret > 0) 739235783Skib return (u32) ret; 740235783Skib } 741235783Skib 742235783Skib /* GPU high precision timestamp query unsupported or failed. 743280183Sdumbbell * Return current monotonic/gettimeofday timestamp as best estimate. 744235783Skib */ 745280183Sdumbbell *tvblank = get_drm_timestamp(); 746235783Skib 747235783Skib return 0; 748235783Skib} 749280183SdumbbellEXPORT_SYMBOL(drm_get_last_vbltimestamp); 750235783Skib 751235783Skib/** 752235783Skib * drm_vblank_count - retrieve "cooked" vblank counter value 753235783Skib * @dev: DRM device 754235783Skib * @crtc: which counter to retrieve 755235783Skib * 756235783Skib * Fetches the "cooked" vblank count value that represents the number of 757235783Skib * vblank events since the system was booted, including lost events due to 758235783Skib * modesetting activity. 759235783Skib */ 760235783Skibu32 drm_vblank_count(struct drm_device *dev, int crtc) 761235783Skib{ 762235783Skib return atomic_read(&dev->_vblank_count[crtc]); 763235783Skib} 764280183SdumbbellEXPORT_SYMBOL(drm_vblank_count); 765235783Skib 766235783Skib/** 767235783Skib * drm_vblank_count_and_time - retrieve "cooked" vblank counter value 768235783Skib * and the system timestamp corresponding to that vblank counter value. 769235783Skib * 770235783Skib * @dev: DRM device 771235783Skib * @crtc: which counter to retrieve 772235783Skib * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. 773235783Skib * 774235783Skib * Fetches the "cooked" vblank count value that represents the number of 775235783Skib * vblank events since the system was booted, including lost events due to 776235783Skib * modesetting activity. Returns corresponding system timestamp of the time 777235783Skib * of the vblank interval that corresponds to the current value vblank counter 778235783Skib * value. 779235783Skib */ 780235783Skibu32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, 781235783Skib struct timeval *vblanktime) 782235783Skib{ 783235783Skib u32 cur_vblank; 784235783Skib 785235783Skib /* Read timestamp from slot of _vblank_time ringbuffer 786235783Skib * that corresponds to current vblank count. Retry if 787235783Skib * count has incremented during readout. This works like 788235783Skib * a seqlock. 789235783Skib */ 790235783Skib do { 791235783Skib cur_vblank = atomic_read(&dev->_vblank_count[crtc]); 792235783Skib *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); 793280183Sdumbbell smp_rmb(); 794235783Skib } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); 795235783Skib 796235783Skib return cur_vblank; 797235783Skib} 798280183SdumbbellEXPORT_SYMBOL(drm_vblank_count_and_time); 799235783Skib 800280183Sdumbbellstatic void send_vblank_event(struct drm_device *dev, 801280183Sdumbbell struct drm_pending_vblank_event *e, 802280183Sdumbbell unsigned long seq, struct timeval *now) 803280183Sdumbbell{ 804280183Sdumbbell WARN_ON_SMP(!mtx_owned(&dev->event_lock)); 805280183Sdumbbell e->event.sequence = seq; 806280183Sdumbbell e->event.tv_sec = now->tv_sec; 807280183Sdumbbell e->event.tv_usec = now->tv_usec; 808280183Sdumbbell 809280183Sdumbbell list_add_tail(&e->base.link, 810280183Sdumbbell &e->base.file_priv->event_list); 811280183Sdumbbell drm_event_wakeup(&e->base); 812280183Sdumbbell CTR3(KTR_DRM, "vblank_event_delivered %d %d %d", 813280183Sdumbbell e->base.pid, e->pipe, e->event.sequence); 814280183Sdumbbell} 815280183Sdumbbell 816235783Skib/** 817280183Sdumbbell * drm_send_vblank_event - helper to send vblank event after pageflip 818280183Sdumbbell * @dev: DRM device 819280183Sdumbbell * @crtc: CRTC in question 820280183Sdumbbell * @e: the event to send 821280183Sdumbbell * 822280183Sdumbbell * Updates sequence # and timestamp on event, and sends it to userspace. 823280183Sdumbbell * Caller must hold event lock. 824280183Sdumbbell */ 825280183Sdumbbellvoid drm_send_vblank_event(struct drm_device *dev, int crtc, 826280183Sdumbbell struct drm_pending_vblank_event *e) 827280183Sdumbbell{ 828280183Sdumbbell struct timeval now; 829280183Sdumbbell unsigned int seq; 830280183Sdumbbell if (crtc >= 0) { 831280183Sdumbbell seq = drm_vblank_count_and_time(dev, crtc, &now); 832280183Sdumbbell } else { 833280183Sdumbbell seq = 0; 834280183Sdumbbell 835280183Sdumbbell now = get_drm_timestamp(); 836280183Sdumbbell } 837280183Sdumbbell send_vblank_event(dev, e, seq, &now); 838280183Sdumbbell} 839280183SdumbbellEXPORT_SYMBOL(drm_send_vblank_event); 840280183Sdumbbell 841280183Sdumbbell/** 842235783Skib * drm_update_vblank_count - update the master vblank counter 843235783Skib * @dev: DRM device 844235783Skib * @crtc: counter to update 845235783Skib * 846235783Skib * Call back into the driver to update the appropriate vblank counter 847235783Skib * (specified by @crtc). Deal with wraparound, if it occurred, and 848235783Skib * update the last read value so we can deal with wraparound on the next 849235783Skib * call if necessary. 850235783Skib * 851235783Skib * Only necessary when going from off->on, to account for frames we 852235783Skib * didn't get an interrupt for. 853235783Skib * 854235783Skib * Note: caller must hold dev->vbl_lock since this reads & writes 855235783Skib * device vblank fields. 856235783Skib */ 857235783Skibstatic void drm_update_vblank_count(struct drm_device *dev, int crtc) 858235783Skib{ 859235783Skib u32 cur_vblank, diff, tslot, rc; 860235783Skib struct timeval t_vblank; 861235783Skib 862235783Skib /* 863235783Skib * Interrupts were disabled prior to this call, so deal with counter 864235783Skib * wrap if needed. 865235783Skib * NOTE! It's possible we lost a full dev->max_vblank_count events 866235783Skib * here if the register is small or we had vblank interrupts off for 867235783Skib * a long time. 868235783Skib * 869235783Skib * We repeat the hardware vblank counter & timestamp query until 870235783Skib * we get consistent results. This to prevent races between gpu 871235783Skib * updating its hardware counter while we are retrieving the 872235783Skib * corresponding vblank timestamp. 873235783Skib */ 874235783Skib do { 875235783Skib cur_vblank = dev->driver->get_vblank_counter(dev, crtc); 876235783Skib rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); 877235783Skib } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); 878235783Skib 879235783Skib /* Deal with counter wrap */ 880235783Skib diff = cur_vblank - dev->last_vblank[crtc]; 881235783Skib if (cur_vblank < dev->last_vblank[crtc]) { 882235783Skib diff += dev->max_vblank_count; 883235783Skib 884235783Skib DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", 885235783Skib crtc, dev->last_vblank[crtc], cur_vblank, diff); 886235783Skib } 887235783Skib 888235783Skib DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", 889235783Skib crtc, diff); 890235783Skib 891235783Skib /* Reinitialize corresponding vblank timestamp if high-precision query 892235783Skib * available. Skip this step if query unsupported or failed. Will 893235783Skib * reinitialize delayed at next vblank interrupt in that case. 894235783Skib */ 895235783Skib if (rc) { 896235783Skib tslot = atomic_read(&dev->_vblank_count[crtc]) + diff; 897235783Skib vblanktimestamp(dev, crtc, tslot) = t_vblank; 898235783Skib } 899235783Skib 900280183Sdumbbell smp_mb__before_atomic_inc(); 901235783Skib atomic_add(diff, &dev->_vblank_count[crtc]); 902280183Sdumbbell smp_mb__after_atomic_inc(); 903235783Skib} 904235783Skib 905235783Skib/** 906235783Skib * drm_vblank_get - get a reference count on vblank events 907235783Skib * @dev: DRM device 908235783Skib * @crtc: which CRTC to own 909235783Skib * 910235783Skib * Acquire a reference count on vblank events to avoid having them disabled 911235783Skib * while in use. 912235783Skib * 913235783Skib * RETURNS 914235783Skib * Zero on success, nonzero on failure. 915235783Skib */ 916235783Skibint drm_vblank_get(struct drm_device *dev, int crtc) 917235783Skib{ 918235783Skib int ret = 0; 919235783Skib 920235783Skib mtx_lock(&dev->vbl_lock); 921235783Skib /* Going from 0->1 means we have to enable interrupts again */ 922254880Sdumbbell if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { 923235783Skib mtx_lock(&dev->vblank_time_lock); 924235783Skib if (!dev->vblank_enabled[crtc]) { 925235783Skib /* Enable vblank irqs under vblank_time_lock protection. 926235783Skib * All vblank count & timestamp updates are held off 927235783Skib * until we are done reinitializing master counter and 928235783Skib * timestamps. Filtercode in drm_handle_vblank() will 929235783Skib * prevent double-accounting of same vblank interval. 930235783Skib */ 931280183Sdumbbell ret = dev->driver->enable_vblank(dev, crtc); 932235783Skib DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", 933235783Skib crtc, ret); 934235783Skib if (ret) 935235783Skib atomic_dec(&dev->vblank_refcount[crtc]); 936235783Skib else { 937235783Skib dev->vblank_enabled[crtc] = 1; 938235783Skib drm_update_vblank_count(dev, crtc); 939235783Skib } 940235783Skib } 941235783Skib mtx_unlock(&dev->vblank_time_lock); 942235783Skib } else { 943235783Skib if (!dev->vblank_enabled[crtc]) { 944235783Skib atomic_dec(&dev->vblank_refcount[crtc]); 945280183Sdumbbell ret = -EINVAL; 946235783Skib } 947235783Skib } 948235783Skib mtx_unlock(&dev->vbl_lock); 949235783Skib 950235783Skib return ret; 951235783Skib} 952280183SdumbbellEXPORT_SYMBOL(drm_vblank_get); 953235783Skib 954235783Skib/** 955235783Skib * drm_vblank_put - give up ownership of vblank events 956235783Skib * @dev: DRM device 957235783Skib * @crtc: which counter to give up 958235783Skib * 959235783Skib * Release ownership of a given vblank counter, turning off interrupts 960235783Skib * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. 961235783Skib */ 962235783Skibvoid drm_vblank_put(struct drm_device *dev, int crtc) 963235783Skib{ 964280183Sdumbbell BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0); 965235783Skib 966235783Skib /* Last user schedules interrupt disable */ 967254880Sdumbbell if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) && 968235783Skib (drm_vblank_offdelay > 0)) 969235783Skib callout_reset(&dev->vblank_disable_callout, 970235783Skib (drm_vblank_offdelay * DRM_HZ) / 1000, 971235783Skib vblank_disable_fn, dev); 972235783Skib} 973280183SdumbbellEXPORT_SYMBOL(drm_vblank_put); 974235783Skib 975280183Sdumbbell/** 976280183Sdumbbell * drm_vblank_off - disable vblank events on a CRTC 977280183Sdumbbell * @dev: DRM device 978280183Sdumbbell * @crtc: CRTC in question 979280183Sdumbbell * 980280183Sdumbbell * Caller must hold event lock. 981280183Sdumbbell */ 982235783Skibvoid drm_vblank_off(struct drm_device *dev, int crtc) 983235783Skib{ 984235783Skib struct drm_pending_vblank_event *e, *t; 985235783Skib struct timeval now; 986235783Skib unsigned int seq; 987235783Skib 988235783Skib mtx_lock(&dev->vbl_lock); 989235783Skib vblank_disable_and_save(dev, crtc); 990280183Sdumbbell DRM_WAKEUP(&dev->_vblank_count[crtc]); 991235783Skib 992235783Skib /* Send any queued vblank events, lest the natives grow disquiet */ 993235783Skib seq = drm_vblank_count_and_time(dev, crtc, &now); 994280183Sdumbbell 995280183Sdumbbell mtx_lock(&dev->event_lock); 996235783Skib list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 997235783Skib if (e->pipe != crtc) 998235783Skib continue; 999235783Skib DRM_DEBUG("Sending premature vblank event on disable: \ 1000235783Skib wanted %d, current %d\n", 1001235783Skib e->event.sequence, seq); 1002280183Sdumbbell list_del(&e->base.link); 1003235783Skib drm_vblank_put(dev, e->pipe); 1004280183Sdumbbell send_vblank_event(dev, e, seq, &now); 1005235783Skib } 1006280183Sdumbbell mtx_unlock(&dev->event_lock); 1007235783Skib 1008235783Skib mtx_unlock(&dev->vbl_lock); 1009235783Skib} 1010280183SdumbbellEXPORT_SYMBOL(drm_vblank_off); 1011235783Skib 1012235783Skib/** 1013235783Skib * drm_vblank_pre_modeset - account for vblanks across mode sets 1014235783Skib * @dev: DRM device 1015235783Skib * @crtc: CRTC in question 1016235783Skib * 1017235783Skib * Account for vblank events across mode setting events, which will likely 1018235783Skib * reset the hardware frame counter. 1019235783Skib */ 1020235783Skibvoid drm_vblank_pre_modeset(struct drm_device *dev, int crtc) 1021235783Skib{ 1022279599Sdumbbell /* vblank is not initialized (IRQ not installed ?), or has been freed */ 1023235783Skib if (!dev->num_crtcs) 1024235783Skib return; 1025235783Skib /* 1026235783Skib * To avoid all the problems that might happen if interrupts 1027235783Skib * were enabled/disabled around or between these calls, we just 1028235783Skib * have the kernel take a reference on the CRTC (just once though 1029235783Skib * to avoid corrupting the count if multiple, mismatch calls occur), 1030235783Skib * so that interrupts remain enabled in the interim. 1031235783Skib */ 1032235783Skib if (!dev->vblank_inmodeset[crtc]) { 1033235783Skib dev->vblank_inmodeset[crtc] = 0x1; 1034235783Skib if (drm_vblank_get(dev, crtc) == 0) 1035235783Skib dev->vblank_inmodeset[crtc] |= 0x2; 1036235783Skib } 1037235783Skib} 1038280183SdumbbellEXPORT_SYMBOL(drm_vblank_pre_modeset); 1039235783Skib 1040235783Skibvoid drm_vblank_post_modeset(struct drm_device *dev, int crtc) 1041235783Skib{ 1042279599Sdumbbell /* vblank is not initialized (IRQ not installed ?), or has been freed */ 1043279599Sdumbbell if (!dev->num_crtcs) 1044279599Sdumbbell return; 1045235783Skib 1046235783Skib if (dev->vblank_inmodeset[crtc]) { 1047235783Skib mtx_lock(&dev->vbl_lock); 1048235783Skib dev->vblank_disable_allowed = 1; 1049235783Skib mtx_unlock(&dev->vbl_lock); 1050235783Skib 1051235783Skib if (dev->vblank_inmodeset[crtc] & 0x2) 1052235783Skib drm_vblank_put(dev, crtc); 1053235783Skib 1054235783Skib dev->vblank_inmodeset[crtc] = 0; 1055235783Skib } 1056235783Skib} 1057280183SdumbbellEXPORT_SYMBOL(drm_vblank_post_modeset); 1058235783Skib 1059235783Skib/** 1060235783Skib * drm_modeset_ctl - handle vblank event counter changes across mode switch 1061235783Skib * @DRM_IOCTL_ARGS: standard ioctl arguments 1062235783Skib * 1063235783Skib * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET 1064235783Skib * ioctls around modesetting so that any lost vblank events are accounted for. 1065235783Skib * 1066235783Skib * Generally the counter will reset across mode sets. If interrupts are 1067235783Skib * enabled around this call, we don't have to do anything since the counter 1068235783Skib * will have already been incremented. 1069235783Skib */ 1070235783Skibint drm_modeset_ctl(struct drm_device *dev, void *data, 1071235783Skib struct drm_file *file_priv) 1072235783Skib{ 1073235783Skib struct drm_modeset_ctl *modeset = data; 1074235783Skib unsigned int crtc; 1075235783Skib 1076235783Skib /* If drm_vblank_init() hasn't been called yet, just no-op */ 1077235783Skib if (!dev->num_crtcs) 1078277487Skib return 0; 1079235783Skib 1080280183Sdumbbell /* KMS drivers handle this internally */ 1081280183Sdumbbell if (drm_core_check_feature(dev, DRIVER_MODESET)) 1082280183Sdumbbell return 0; 1083280183Sdumbbell 1084235783Skib crtc = modeset->crtc; 1085277487Skib if (crtc >= dev->num_crtcs) 1086277487Skib return -EINVAL; 1087235783Skib 1088235783Skib switch (modeset->cmd) { 1089235783Skib case _DRM_PRE_MODESET: 1090235783Skib drm_vblank_pre_modeset(dev, crtc); 1091235783Skib break; 1092235783Skib case _DRM_POST_MODESET: 1093235783Skib drm_vblank_post_modeset(dev, crtc); 1094235783Skib break; 1095235783Skib default: 1096277487Skib return -EINVAL; 1097235783Skib } 1098235783Skib 1099277487Skib return 0; 1100235783Skib} 1101235783Skib 1102235783Skibstatic void 1103235783Skibdrm_vblank_event_destroy(struct drm_pending_event *e) 1104235783Skib{ 1105235783Skib 1106235783Skib free(e, DRM_MEM_VBLANK); 1107235783Skib} 1108235783Skib 1109235783Skibstatic int drm_queue_vblank_event(struct drm_device *dev, int pipe, 1110235783Skib union drm_wait_vblank *vblwait, 1111235783Skib struct drm_file *file_priv) 1112235783Skib{ 1113235783Skib struct drm_pending_vblank_event *e; 1114235783Skib struct timeval now; 1115235783Skib unsigned int seq; 1116235783Skib int ret; 1117235783Skib 1118280183Sdumbbell e = malloc(sizeof *e, DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); 1119280183Sdumbbell if (e == NULL) { 1120280183Sdumbbell ret = -ENOMEM; 1121280183Sdumbbell goto err_put; 1122280183Sdumbbell } 1123235783Skib 1124235783Skib e->pipe = pipe; 1125235783Skib e->base.pid = curproc->p_pid; 1126235783Skib e->event.base.type = DRM_EVENT_VBLANK; 1127235783Skib e->event.base.length = sizeof e->event; 1128235783Skib e->event.user_data = vblwait->request.signal; 1129235783Skib e->base.event = &e->event.base; 1130235783Skib e->base.file_priv = file_priv; 1131235783Skib e->base.destroy = drm_vblank_event_destroy; 1132235783Skib 1133235783Skib mtx_lock(&dev->event_lock); 1134235783Skib 1135235783Skib if (file_priv->event_space < sizeof e->event) { 1136280183Sdumbbell ret = -EBUSY; 1137235783Skib goto err_unlock; 1138235783Skib } 1139235783Skib 1140235783Skib file_priv->event_space -= sizeof e->event; 1141235783Skib seq = drm_vblank_count_and_time(dev, pipe, &now); 1142235783Skib 1143235783Skib if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && 1144235783Skib (seq - vblwait->request.sequence) <= (1 << 23)) { 1145235783Skib vblwait->request.sequence = seq + 1; 1146235783Skib vblwait->reply.sequence = vblwait->request.sequence; 1147235783Skib } 1148235783Skib 1149235783Skib DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n", 1150235783Skib vblwait->request.sequence, seq, pipe); 1151235783Skib 1152235783Skib CTR4(KTR_DRM, "vblank_event_queued %d %d rt %x %d", curproc->p_pid, pipe, 1153235783Skib vblwait->request.type, vblwait->request.sequence); 1154235783Skib 1155235783Skib e->event.sequence = vblwait->request.sequence; 1156235783Skib if ((seq - vblwait->request.sequence) <= (1 << 23)) { 1157235783Skib drm_vblank_put(dev, pipe); 1158280183Sdumbbell send_vblank_event(dev, e, seq, &now); 1159235783Skib vblwait->reply.sequence = seq; 1160235783Skib } else { 1161235783Skib /* drm_handle_vblank_events will call drm_vblank_put */ 1162235783Skib list_add_tail(&e->base.link, &dev->vblank_event_list); 1163235783Skib vblwait->reply.sequence = vblwait->request.sequence; 1164235783Skib } 1165235783Skib 1166235783Skib mtx_unlock(&dev->event_lock); 1167235783Skib 1168235783Skib return 0; 1169235783Skib 1170235783Skiberr_unlock: 1171235783Skib mtx_unlock(&dev->event_lock); 1172235783Skib free(e, DRM_MEM_VBLANK); 1173280183Sdumbbellerr_put: 1174235783Skib drm_vblank_put(dev, pipe); 1175235783Skib return ret; 1176235783Skib} 1177235783Skib 1178235783Skib/** 1179235783Skib * Wait for VBLANK. 1180235783Skib * 1181235783Skib * \param inode device inode. 1182235783Skib * \param file_priv DRM file private. 1183235783Skib * \param cmd command. 1184235783Skib * \param data user argument, pointing to a drm_wait_vblank structure. 1185235783Skib * \return zero on success or a negative number on failure. 1186235783Skib * 1187235783Skib * This function enables the vblank interrupt on the pipe requested, then 1188235783Skib * sleeps waiting for the requested sequence number to occur, and drops 1189235783Skib * the vblank interrupt refcount afterwards. (vblank irq disable follows that 1190235783Skib * after a timeout with no further vblank waits scheduled). 1191235783Skib */ 1192235783Skibint drm_wait_vblank(struct drm_device *dev, void *data, 1193235783Skib struct drm_file *file_priv) 1194235783Skib{ 1195235783Skib union drm_wait_vblank *vblwait = data; 1196277487Skib int ret; 1197235783Skib unsigned int flags, seq, crtc, high_crtc; 1198235783Skib 1199235783Skib if (/*(!drm_dev_to_irq(dev)) || */(!dev->irq_enabled)) 1200280183Sdumbbell return -EINVAL; 1201235783Skib 1202235783Skib if (vblwait->request.type & _DRM_VBLANK_SIGNAL) 1203280183Sdumbbell return -EINVAL; 1204235783Skib 1205235783Skib if (vblwait->request.type & 1206235783Skib ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 1207235783Skib _DRM_VBLANK_HIGH_CRTC_MASK)) { 1208235783Skib DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", 1209235783Skib vblwait->request.type, 1210235783Skib (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 1211235783Skib _DRM_VBLANK_HIGH_CRTC_MASK)); 1212280183Sdumbbell return -EINVAL; 1213235783Skib } 1214235783Skib 1215235783Skib flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 1216235783Skib high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); 1217235783Skib if (high_crtc) 1218235783Skib crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT; 1219235783Skib else 1220235783Skib crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 1221235783Skib if (crtc >= dev->num_crtcs) 1222280183Sdumbbell return -EINVAL; 1223235783Skib 1224235783Skib ret = drm_vblank_get(dev, crtc); 1225235783Skib if (ret) { 1226235783Skib DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); 1227280183Sdumbbell return ret; 1228235783Skib } 1229235783Skib seq = drm_vblank_count(dev, crtc); 1230235783Skib 1231235783Skib switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 1232235783Skib case _DRM_VBLANK_RELATIVE: 1233235783Skib vblwait->request.sequence += seq; 1234235783Skib vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 1235235783Skib case _DRM_VBLANK_ABSOLUTE: 1236235783Skib break; 1237235783Skib default: 1238280183Sdumbbell ret = -EINVAL; 1239235783Skib goto done; 1240235783Skib } 1241235783Skib 1242235783Skib if (flags & _DRM_VBLANK_EVENT) { 1243235783Skib /* must hold on to the vblank ref until the event fires 1244235783Skib * drm_vblank_put will be called asynchronously 1245235783Skib */ 1246235783Skib return drm_queue_vblank_event(dev, crtc, vblwait, file_priv); 1247235783Skib } 1248235783Skib 1249235783Skib if ((flags & _DRM_VBLANK_NEXTONMISS) && 1250235783Skib (seq - vblwait->request.sequence) <= (1<<23)) { 1251235783Skib vblwait->request.sequence = seq + 1; 1252235783Skib } 1253235783Skib 1254280183Sdumbbell DRM_DEBUG("waiting on vblank count %d, crtc %d\n", 1255280183Sdumbbell vblwait->request.sequence, crtc); 1256235783Skib dev->last_vblank_wait[crtc] = vblwait->request.sequence; 1257235783Skib mtx_lock(&dev->vblank_time_lock); 1258235783Skib while (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) > 1259235783Skib (1 << 23)) && dev->irq_enabled) { 1260235783Skib /* 1261235783Skib * The wakeups from the drm_irq_uninstall() and 1262235783Skib * drm_vblank_off() may be lost there since vbl_lock 1263235783Skib * is not held. Then, the timeout will wake us; the 3 1264235783Skib * seconds delay should not be a problem for 1265235783Skib * application when crtc is disabled or irq 1266235783Skib * uninstalled anyway. 1267235783Skib */ 1268280183Sdumbbell ret = -msleep(&dev->_vblank_count[crtc], &dev->vblank_time_lock, 1269235783Skib PCATCH, "drmvbl", 3 * hz); 1270280183Sdumbbell if (ret == -ERESTART) 1271280183Sdumbbell ret = -ERESTARTSYS; 1272235783Skib if (ret != 0) 1273235783Skib break; 1274235783Skib } 1275235783Skib mtx_unlock(&dev->vblank_time_lock); 1276280183Sdumbbell if (ret != -EINTR) { 1277235783Skib struct timeval now; 1278235783Skib long reply_seq; 1279235783Skib 1280235783Skib reply_seq = drm_vblank_count_and_time(dev, crtc, &now); 1281235783Skib CTR5(KTR_DRM, "wait_vblank %d %d rt %x success %d %d", 1282235783Skib curproc->p_pid, crtc, vblwait->request.type, 1283235783Skib vblwait->request.sequence, reply_seq); 1284280183Sdumbbell 1285235783Skib vblwait->reply.sequence = reply_seq; 1286235783Skib vblwait->reply.tval_sec = now.tv_sec; 1287235783Skib vblwait->reply.tval_usec = now.tv_usec; 1288280183Sdumbbell 1289280183Sdumbbell DRM_DEBUG("returning %d to client\n", 1290280183Sdumbbell vblwait->reply.sequence); 1291235783Skib } else { 1292235783Skib CTR5(KTR_DRM, "wait_vblank %d %d rt %x error %d %d", 1293235783Skib curproc->p_pid, crtc, vblwait->request.type, ret, 1294235783Skib vblwait->request.sequence); 1295280183Sdumbbell 1296280183Sdumbbell DRM_DEBUG("vblank wait interrupted by signal\n"); 1297235783Skib } 1298235783Skib 1299235783Skibdone: 1300235783Skib drm_vblank_put(dev, crtc); 1301235783Skib return ret; 1302235783Skib} 1303235783Skib 1304280183Sdumbbellstatic void drm_handle_vblank_events(struct drm_device *dev, int crtc) 1305235783Skib{ 1306235783Skib struct drm_pending_vblank_event *e, *t; 1307235783Skib struct timeval now; 1308235783Skib unsigned int seq; 1309235783Skib 1310235783Skib seq = drm_vblank_count_and_time(dev, crtc, &now); 1311235783Skib 1312235783Skib mtx_lock(&dev->event_lock); 1313235783Skib 1314235783Skib list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 1315235783Skib if (e->pipe != crtc) 1316235783Skib continue; 1317235783Skib if ((seq - e->event.sequence) > (1<<23)) 1318235783Skib continue; 1319235783Skib 1320280183Sdumbbell DRM_DEBUG("vblank event on %d, current %d\n", 1321280183Sdumbbell e->event.sequence, seq); 1322280183Sdumbbell 1323280183Sdumbbell list_del(&e->base.link); 1324235783Skib drm_vblank_put(dev, e->pipe); 1325280183Sdumbbell send_vblank_event(dev, e, seq, &now); 1326235783Skib } 1327235783Skib 1328235783Skib mtx_unlock(&dev->event_lock); 1329280183Sdumbbell 1330280183Sdumbbell CTR2(KTR_DRM, "drm_handle_vblank_events %d %d", seq, crtc); 1331235783Skib} 1332235783Skib 1333235783Skib/** 1334235783Skib * drm_handle_vblank - handle a vblank event 1335235783Skib * @dev: DRM device 1336235783Skib * @crtc: where this event occurred 1337235783Skib * 1338235783Skib * Drivers should call this routine in their vblank interrupt handlers to 1339235783Skib * update the vblank counter and send any signals that may be pending. 1340235783Skib */ 1341235783Skibbool drm_handle_vblank(struct drm_device *dev, int crtc) 1342235783Skib{ 1343235783Skib u32 vblcount; 1344280183Sdumbbell s64 diff_ns; 1345235783Skib struct timeval tvblank; 1346235783Skib 1347235783Skib if (!dev->num_crtcs) 1348235783Skib return false; 1349235783Skib 1350235783Skib /* Need timestamp lock to prevent concurrent execution with 1351235783Skib * vblank enable/disable, as this would cause inconsistent 1352235783Skib * or corrupted timestamps and vblank counts. 1353235783Skib */ 1354235783Skib mtx_lock(&dev->vblank_time_lock); 1355235783Skib 1356235783Skib /* Vblank irq handling disabled. Nothing to do. */ 1357235783Skib if (!dev->vblank_enabled[crtc]) { 1358235783Skib mtx_unlock(&dev->vblank_time_lock); 1359235783Skib return false; 1360235783Skib } 1361235783Skib 1362235783Skib /* Fetch corresponding timestamp for this vblank interval from 1363235783Skib * driver and store it in proper slot of timestamp ringbuffer. 1364235783Skib */ 1365235783Skib 1366235783Skib /* Get current timestamp and count. */ 1367235783Skib vblcount = atomic_read(&dev->_vblank_count[crtc]); 1368235783Skib drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); 1369235783Skib 1370235783Skib /* Compute time difference to timestamp of last vblank */ 1371235783Skib diff_ns = timeval_to_ns(&tvblank) - 1372235783Skib timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); 1373235783Skib 1374235783Skib /* Update vblank timestamp and count if at least 1375235783Skib * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds 1376235783Skib * difference between last stored timestamp and current 1377235783Skib * timestamp. A smaller difference means basically 1378235783Skib * identical timestamps. Happens if this vblank has 1379235783Skib * been already processed and this is a redundant call, 1380235783Skib * e.g., due to spurious vblank interrupts. We need to 1381235783Skib * ignore those for accounting. 1382235783Skib */ 1383235783Skib if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { 1384235783Skib /* Store new timestamp in ringbuffer. */ 1385235783Skib vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; 1386235783Skib 1387235783Skib /* Increment cooked vblank count. This also atomically commits 1388235783Skib * the timestamp computed above. 1389235783Skib */ 1390280183Sdumbbell smp_mb__before_atomic_inc(); 1391235783Skib atomic_inc(&dev->_vblank_count[crtc]); 1392280183Sdumbbell smp_mb__after_atomic_inc(); 1393235783Skib } else { 1394235783Skib DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", 1395235783Skib crtc, (int) diff_ns); 1396235783Skib } 1397235783Skib 1398280183Sdumbbell DRM_WAKEUP(&dev->_vblank_count[crtc]); 1399235783Skib drm_handle_vblank_events(dev, crtc); 1400235783Skib 1401235783Skib mtx_unlock(&dev->vblank_time_lock); 1402235783Skib return true; 1403235783Skib} 1404280183SdumbbellEXPORT_SYMBOL(drm_handle_vblank); 1405