1145132Sanholt/*- 2145132Sanholt * Copyright 2003 Eric Anholt 3145132Sanholt * All Rights Reserved. 4145132Sanholt * 5145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 6145132Sanholt * copy of this software and associated documentation files (the "Software"), 7145132Sanholt * to deal in the Software without restriction, including without limitation 8145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 10145132Sanholt * Software is furnished to do so, subject to the following conditions: 11145132Sanholt * 12145132Sanholt * The above copyright notice and this permission notice (including the next 13145132Sanholt * paragraph) shall be included in all copies or substantial portions of the 14145132Sanholt * Software. 15145132Sanholt * 16145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19145132Sanholt * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20145132Sanholt * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21145132Sanholt * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22145132Sanholt * 23145132Sanholt * Authors: 24145132Sanholt * Eric Anholt <anholt@FreeBSD.org> 25145132Sanholt * 26145132Sanholt */ 27145132Sanholt 28152909Sanholt#include <sys/cdefs.h> 29152909Sanholt__FBSDID("$FreeBSD: stable/11/sys/dev/drm/drm_irq.c 331409 2018-03-23 02:33:30Z emaste $"); 30152909Sanholt 31182080Srnoland/** @file drm_irq.c 32182080Srnoland * Support code for handling setup/teardown of interrupt handlers and 33182080Srnoland * handing interrupt handlers off to the drivers. 34182080Srnoland */ 35182080Srnoland 36145132Sanholt#include "dev/drm/drmP.h" 37145132Sanholt#include "dev/drm/drm.h" 38145132Sanholt 39182080Srnolandint drm_irq_by_busid(struct drm_device *dev, void *data, 40182080Srnoland struct drm_file *file_priv) 41145132Sanholt{ 42183573Srnoland struct drm_irq_busid *irq = data; 43145132Sanholt 44182080Srnoland if ((irq->busnum >> 8) != dev->pci_domain || 45182080Srnoland (irq->busnum & 0xff) != dev->pci_bus || 46182080Srnoland irq->devnum != dev->pci_slot || 47182080Srnoland irq->funcnum != dev->pci_func) 48145132Sanholt return EINVAL; 49145132Sanholt 50182080Srnoland irq->irq = dev->irq; 51145132Sanholt 52145132Sanholt DRM_DEBUG("%d:%d:%d => IRQ %d\n", 53183573Srnoland irq->busnum, irq->devnum, irq->funcnum, irq->irq); 54145132Sanholt 55145132Sanholt return 0; 56145132Sanholt} 57145132Sanholt 58145132Sanholtstatic irqreturn_t 59145132Sanholtdrm_irq_handler_wrap(DRM_IRQ_ARGS) 60145132Sanholt{ 61182080Srnoland struct drm_device *dev = arg; 62145132Sanholt 63145132Sanholt DRM_SPINLOCK(&dev->irq_lock); 64183573Srnoland dev->driver->irq_handler(arg); 65145132Sanholt DRM_SPINUNLOCK(&dev->irq_lock); 66145132Sanholt} 67145132Sanholt 68182080Srnolandstatic void vblank_disable_fn(void *arg) 69145132Sanholt{ 70182080Srnoland struct drm_device *dev = (struct drm_device *)arg; 71182080Srnoland int i; 72182080Srnoland 73194960Srnoland /* Make sure that we are called with the lock held */ 74194960Srnoland mtx_assert(&dev->vbl_lock, MA_OWNED); 75194960Srnoland 76182080Srnoland if (callout_pending(&dev->vblank_disable_timer)) { 77182080Srnoland /* callout was reset */ 78182080Srnoland return; 79182080Srnoland } 80182080Srnoland if (!callout_active(&dev->vblank_disable_timer)) { 81182080Srnoland /* callout was stopped */ 82182080Srnoland return; 83182080Srnoland } 84182080Srnoland callout_deactivate(&dev->vblank_disable_timer); 85182080Srnoland 86190401Srnoland DRM_DEBUG("vblank_disable: %s\n", dev->vblank_disable_allowed ? 87190401Srnoland "allowed" : "denied"); 88182080Srnoland if (!dev->vblank_disable_allowed) 89182080Srnoland return; 90182080Srnoland 91182080Srnoland for (i = 0; i < dev->num_crtcs; i++) { 92194965Srnoland if (dev->vblank[i].refcount == 0 && 93190401Srnoland dev->vblank[i].enabled && !dev->vblank[i].inmodeset) { 94182080Srnoland DRM_DEBUG("disabling vblank on crtc %d\n", i); 95182080Srnoland dev->vblank[i].last = 96183573Srnoland dev->driver->get_vblank_counter(dev, i); 97183573Srnoland dev->driver->disable_vblank(dev, i); 98182080Srnoland dev->vblank[i].enabled = 0; 99182080Srnoland } 100182080Srnoland } 101182080Srnoland} 102182080Srnoland 103189130Srnolandvoid drm_vblank_cleanup(struct drm_device *dev) 104182080Srnoland{ 105182080Srnoland /* Bail if the driver didn't call drm_vblank_init() */ 106182080Srnoland if (dev->num_crtcs == 0) 107183573Srnoland return; 108182080Srnoland 109190022Srnoland DRM_SPINLOCK(&dev->vbl_lock); 110182080Srnoland callout_stop(&dev->vblank_disable_timer); 111190022Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 112182080Srnoland 113182080Srnoland callout_drain(&dev->vblank_disable_timer); 114182080Srnoland 115194960Srnoland DRM_SPINLOCK(&dev->vbl_lock); 116182080Srnoland vblank_disable_fn((void *)dev); 117194960Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 118182080Srnoland 119183833Srnoland free(dev->vblank, DRM_MEM_DRIVER); 120182080Srnoland 121182080Srnoland dev->num_crtcs = 0; 122182080Srnoland} 123182080Srnoland 124182080Srnolandint drm_vblank_init(struct drm_device *dev, int num_crtcs) 125182080Srnoland{ 126182080Srnoland int i, ret = ENOMEM; 127182080Srnoland 128182080Srnoland callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); 129182080Srnoland dev->num_crtcs = num_crtcs; 130182080Srnoland 131183833Srnoland dev->vblank = malloc(sizeof(struct drm_vblank_info) * num_crtcs, 132183833Srnoland DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 133182080Srnoland if (!dev->vblank) 134182080Srnoland goto err; 135182080Srnoland 136183573Srnoland DRM_DEBUG("\n"); 137183573Srnoland 138182080Srnoland /* Zero per-crtc vblank stuff */ 139194963Srnoland DRM_SPINLOCK(&dev->vbl_lock); 140182080Srnoland for (i = 0; i < num_crtcs; i++) { 141182080Srnoland DRM_INIT_WAITQUEUE(&dev->vblank[i].queue); 142194963Srnoland dev->vblank[i].refcount = 0; 143216374Savg atomic_store_rel_32(&dev->vblank[i].count, 0); 144182080Srnoland } 145182080Srnoland dev->vblank_disable_allowed = 0; 146194963Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 147182080Srnoland 148182080Srnoland return 0; 149182080Srnoland 150182080Srnolanderr: 151182080Srnoland drm_vblank_cleanup(dev); 152182080Srnoland return ret; 153182080Srnoland} 154182080Srnoland 155182080Srnolandint drm_irq_install(struct drm_device *dev) 156182080Srnoland{ 157190401Srnoland int crtc, retcode; 158145132Sanholt 159145132Sanholt if (dev->irq == 0 || dev->dev_private == NULL) 160182080Srnoland return EINVAL; 161145132Sanholt 162183573Srnoland DRM_DEBUG("irq=%d\n", dev->irq); 163145132Sanholt 164145132Sanholt DRM_LOCK(); 165145132Sanholt if (dev->irq_enabled) { 166145132Sanholt DRM_UNLOCK(); 167182080Srnoland return EBUSY; 168145132Sanholt } 169145132Sanholt dev->irq_enabled = 1; 170145132Sanholt 171145132Sanholt dev->context_flag = 0; 172145132Sanholt 173183573Srnoland /* Before installing handler */ 174183573Srnoland dev->driver->irq_preinstall(dev); 175145132Sanholt DRM_UNLOCK(); 176145132Sanholt 177183573Srnoland /* Install handler */ 178182080Srnoland retcode = bus_setup_intr(dev->device, dev->irqr, 179182080Srnoland INTR_TYPE_TTY | INTR_MPSAFE, 180182080Srnoland NULL, drm_irq_handler_wrap, dev, &dev->irqh); 181145132Sanholt if (retcode != 0) 182145132Sanholt goto err; 183145132Sanholt 184183573Srnoland /* After installing handler */ 185145132Sanholt DRM_LOCK(); 186183573Srnoland dev->driver->irq_postinstall(dev); 187145132Sanholt DRM_UNLOCK(); 188190401Srnoland if (dev->driver->enable_vblank) { 189190401Srnoland DRM_SPINLOCK(&dev->vbl_lock); 190190401Srnoland for( crtc = 0 ; crtc < dev->num_crtcs ; crtc++) { 191190401Srnoland if (dev->driver->enable_vblank(dev, crtc) == 0) { 192190401Srnoland dev->vblank[crtc].enabled = 1; 193190401Srnoland } 194190401Srnoland } 195190401Srnoland callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, 196190401Srnoland (timeout_t *)vblank_disable_fn, (void *)dev); 197190401Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 198190401Srnoland } 199145132Sanholt 200145132Sanholt return 0; 201145132Sanholterr: 202145132Sanholt DRM_LOCK(); 203145132Sanholt dev->irq_enabled = 0; 204145132Sanholt DRM_UNLOCK(); 205189052Srnoland 206145132Sanholt return retcode; 207145132Sanholt} 208145132Sanholt 209182080Srnolandint drm_irq_uninstall(struct drm_device *dev) 210145132Sanholt{ 211190022Srnoland int crtc; 212190022Srnoland 213145132Sanholt if (!dev->irq_enabled) 214182080Srnoland return EINVAL; 215145132Sanholt 216145132Sanholt dev->irq_enabled = 0; 217145132Sanholt 218190022Srnoland /* 219190022Srnoland * Wake up any waiters so they don't hang. 220190022Srnoland */ 221190022Srnoland DRM_SPINLOCK(&dev->vbl_lock); 222190022Srnoland for (crtc = 0; crtc < dev->num_crtcs; crtc++) { 223190125Srnoland if (dev->vblank[crtc].enabled) { 224190125Srnoland DRM_WAKEUP(&dev->vblank[crtc].queue); 225190401Srnoland dev->vblank[crtc].last = 226190401Srnoland dev->driver->get_vblank_counter(dev, crtc); 227190125Srnoland dev->vblank[crtc].enabled = 0; 228190125Srnoland } 229190022Srnoland } 230190022Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 231190022Srnoland 232183573Srnoland DRM_DEBUG("irq=%d\n", dev->irq); 233145132Sanholt 234183573Srnoland dev->driver->irq_uninstall(dev); 235145132Sanholt 236145132Sanholt DRM_UNLOCK(); 237145132Sanholt bus_teardown_intr(dev->device, dev->irqr, dev->irqh); 238145132Sanholt DRM_LOCK(); 239183573Srnoland 240145132Sanholt return 0; 241145132Sanholt} 242145132Sanholt 243182080Srnolandint drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) 244145132Sanholt{ 245183573Srnoland struct drm_control *ctl = data; 246145132Sanholt int err; 247145132Sanholt 248183573Srnoland switch (ctl->func) { 249145132Sanholt case DRM_INST_HANDLER: 250145132Sanholt /* Handle drivers whose DRM used to require IRQ setup but the 251145132Sanholt * no longer does. 252145132Sanholt */ 253183573Srnoland if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 254145132Sanholt return 0; 255145132Sanholt if (dev->if_version < DRM_IF_VERSION(1, 2) && 256182080Srnoland ctl->irq != dev->irq) 257182080Srnoland return EINVAL; 258145132Sanholt return drm_irq_install(dev); 259145132Sanholt case DRM_UNINST_HANDLER: 260183573Srnoland if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 261145132Sanholt return 0; 262145132Sanholt DRM_LOCK(); 263145132Sanholt err = drm_irq_uninstall(dev); 264145132Sanholt DRM_UNLOCK(); 265145132Sanholt return err; 266145132Sanholt default: 267182080Srnoland return EINVAL; 268145132Sanholt } 269145132Sanholt} 270145132Sanholt 271182080Srnolandu32 drm_vblank_count(struct drm_device *dev, int crtc) 272145132Sanholt{ 273194963Srnoland return atomic_load_acq_32(&dev->vblank[crtc].count); 274182080Srnoland} 275145132Sanholt 276182080Srnolandstatic void drm_update_vblank_count(struct drm_device *dev, int crtc) 277182080Srnoland{ 278182080Srnoland u32 cur_vblank, diff; 279182080Srnoland 280182080Srnoland /* 281182080Srnoland * Interrupts were disabled prior to this call, so deal with counter 282182080Srnoland * wrap if needed. 283182080Srnoland * NOTE! It's possible we lost a full dev->max_vblank_count events 284182080Srnoland * here if the register is small or we had vblank interrupts off for 285182080Srnoland * a long time. 286182080Srnoland */ 287183573Srnoland cur_vblank = dev->driver->get_vblank_counter(dev, crtc); 288182080Srnoland diff = cur_vblank - dev->vblank[crtc].last; 289182080Srnoland if (cur_vblank < dev->vblank[crtc].last) { 290182080Srnoland diff += dev->max_vblank_count; 291182080Srnoland 292183573Srnoland DRM_DEBUG("vblank[%d].last=0x%x, cur_vblank=0x%x => diff=0x%x\n", 293182080Srnoland crtc, dev->vblank[crtc].last, cur_vblank, diff); 294182080Srnoland } 295182080Srnoland 296182080Srnoland DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", 297182080Srnoland crtc, diff); 298182080Srnoland 299194963Srnoland atomic_add_rel_32(&dev->vblank[crtc].count, diff); 300182080Srnoland} 301182080Srnoland 302182080Srnolandint drm_vblank_get(struct drm_device *dev, int crtc) 303182080Srnoland{ 304182080Srnoland int ret = 0; 305182080Srnoland 306194963Srnoland /* Make sure that we are called with the lock held */ 307194963Srnoland mtx_assert(&dev->vbl_lock, MA_OWNED); 308194963Srnoland 309182080Srnoland /* Going from 0->1 means we have to enable interrupts again */ 310194963Srnoland if (++dev->vblank[crtc].refcount == 1 && 311182080Srnoland !dev->vblank[crtc].enabled) { 312183573Srnoland ret = dev->driver->enable_vblank(dev, crtc); 313190022Srnoland DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); 314182080Srnoland if (ret) 315194963Srnoland --dev->vblank[crtc].refcount; 316182080Srnoland else { 317182080Srnoland dev->vblank[crtc].enabled = 1; 318182080Srnoland drm_update_vblank_count(dev, crtc); 319182080Srnoland } 320182080Srnoland } 321182080Srnoland 322194966Srnoland if (dev->vblank[crtc].enabled) 323194966Srnoland dev->vblank[crtc].last = 324194966Srnoland dev->driver->get_vblank_counter(dev, crtc); 325194966Srnoland 326182080Srnoland return ret; 327182080Srnoland} 328182080Srnoland 329182080Srnolandvoid drm_vblank_put(struct drm_device *dev, int crtc) 330182080Srnoland{ 331194963Srnoland /* Make sure that we are called with the lock held */ 332194963Srnoland mtx_assert(&dev->vbl_lock, MA_OWNED); 333194963Srnoland 334194963Srnoland KASSERT(dev->vblank[crtc].refcount > 0, 335190022Srnoland ("invalid refcount")); 336182080Srnoland 337182080Srnoland /* Last user schedules interrupt disable */ 338194963Srnoland if (--dev->vblank[crtc].refcount == 0) 339182080Srnoland callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, 340182080Srnoland (timeout_t *)vblank_disable_fn, (void *)dev); 341182080Srnoland} 342182080Srnoland 343182080Srnolandint drm_modeset_ctl(struct drm_device *dev, void *data, 344182080Srnoland struct drm_file *file_priv) 345182080Srnoland{ 346182080Srnoland struct drm_modeset_ctl *modeset = data; 347182080Srnoland int crtc, ret = 0; 348182080Srnoland 349182080Srnoland /* If drm_vblank_init() hasn't been called yet, just no-op */ 350182080Srnoland if (!dev->num_crtcs) 351183573Srnoland goto out; 352182080Srnoland 353182080Srnoland crtc = modeset->crtc; 354331409Semaste if (crtc < 0 || crtc >= dev->num_crtcs) { 355182080Srnoland ret = EINVAL; 356182080Srnoland goto out; 357182080Srnoland } 358182080Srnoland 359182080Srnoland /* 360182080Srnoland * To avoid all the problems that might happen if interrupts 361182080Srnoland * were enabled/disabled around or between these calls, we just 362182080Srnoland * have the kernel take a reference on the CRTC (just once though 363182080Srnoland * to avoid corrupting the count if multiple, mismatch calls occur), 364182080Srnoland * so that interrupts remain enabled in the interim. 365182080Srnoland */ 366182080Srnoland switch (modeset->cmd) { 367182080Srnoland case _DRM_PRE_MODESET: 368194963Srnoland DRM_DEBUG("pre-modeset, crtc %d\n", crtc); 369194963Srnoland DRM_SPINLOCK(&dev->vbl_lock); 370182080Srnoland if (!dev->vblank[crtc].inmodeset) { 371190022Srnoland dev->vblank[crtc].inmodeset = 0x1; 372190022Srnoland if (drm_vblank_get(dev, crtc) == 0) 373190022Srnoland dev->vblank[crtc].inmodeset |= 0x2; 374182080Srnoland } 375194963Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 376182080Srnoland break; 377182080Srnoland case _DRM_POST_MODESET: 378194963Srnoland DRM_DEBUG("post-modeset, crtc %d\n", crtc); 379194963Srnoland DRM_SPINLOCK(&dev->vbl_lock); 380182080Srnoland if (dev->vblank[crtc].inmodeset) { 381190022Srnoland if (dev->vblank[crtc].inmodeset & 0x2) 382190022Srnoland drm_vblank_put(dev, crtc); 383182080Srnoland dev->vblank[crtc].inmodeset = 0; 384182080Srnoland } 385194963Srnoland dev->vblank_disable_allowed = 1; 386194963Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 387182080Srnoland break; 388182080Srnoland default: 389182080Srnoland ret = EINVAL; 390182080Srnoland break; 391182080Srnoland } 392182080Srnoland 393182080Srnolandout: 394182080Srnoland return ret; 395182080Srnoland} 396182080Srnoland 397182080Srnolandint drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) 398182080Srnoland{ 399183573Srnoland union drm_wait_vblank *vblwait = data; 400189050Srnoland unsigned int flags, seq, crtc; 401182080Srnoland int ret = 0; 402182080Srnoland 403145132Sanholt if (!dev->irq_enabled) 404182080Srnoland return EINVAL; 405145132Sanholt 406182080Srnoland if (vblwait->request.type & 407182080Srnoland ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { 408182080Srnoland DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", 409182080Srnoland vblwait->request.type, 410182080Srnoland (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); 411182080Srnoland return EINVAL; 412182080Srnoland } 413145132Sanholt 414182080Srnoland flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 415182080Srnoland crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 416182080Srnoland 417182080Srnoland if (crtc >= dev->num_crtcs) 418182080Srnoland return EINVAL; 419182080Srnoland 420194963Srnoland DRM_SPINLOCK(&dev->vbl_lock); 421182080Srnoland ret = drm_vblank_get(dev, crtc); 422194963Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 423189050Srnoland if (ret) { 424189050Srnoland DRM_ERROR("failed to acquire vblank counter, %d\n", ret); 425183573Srnoland return ret; 426189050Srnoland } 427182080Srnoland seq = drm_vblank_count(dev, crtc); 428182080Srnoland 429182080Srnoland switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 430182080Srnoland case _DRM_VBLANK_RELATIVE: 431182080Srnoland vblwait->request.sequence += seq; 432182080Srnoland vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 433182080Srnoland case _DRM_VBLANK_ABSOLUTE: 434182080Srnoland break; 435182080Srnoland default: 436182080Srnoland ret = EINVAL; 437182080Srnoland goto done; 438145132Sanholt } 439145132Sanholt 440182080Srnoland if ((flags & _DRM_VBLANK_NEXTONMISS) && 441182080Srnoland (seq - vblwait->request.sequence) <= (1<<23)) { 442182080Srnoland vblwait->request.sequence = seq + 1; 443182080Srnoland } 444182080Srnoland 445145132Sanholt if (flags & _DRM_VBLANK_SIGNAL) { 446194748Srnoland /* There have never been any consumers */ 447145132Sanholt ret = EINVAL; 448145132Sanholt } else { 449189050Srnoland DRM_DEBUG("waiting on vblank count %d, crtc %d\n", 450189050Srnoland vblwait->request.sequence, crtc); 451190401Srnoland for ( ret = 0 ; !ret && !(((drm_vblank_count(dev, crtc) - 452190401Srnoland vblwait->request.sequence) <= (1 << 23)) || 453190401Srnoland !dev->irq_enabled) ; ) { 454190433Srnoland mtx_lock(&dev->irq_lock); 455190433Srnoland if (!(((drm_vblank_count(dev, crtc) - 456190433Srnoland vblwait->request.sequence) <= (1 << 23)) || 457190433Srnoland !dev->irq_enabled)) 458190433Srnoland ret = mtx_sleep(&dev->vblank[crtc].queue, 459190433Srnoland &dev->irq_lock, PCATCH, "vblwtq", 460194746Srnoland DRM_HZ); 461190433Srnoland mtx_unlock(&dev->irq_lock); 462189050Srnoland } 463182080Srnoland 464190401Srnoland if (ret != EINTR && ret != ERESTART) { 465182080Srnoland struct timeval now; 466182080Srnoland 467182080Srnoland microtime(&now); 468182080Srnoland vblwait->reply.tval_sec = now.tv_sec; 469182080Srnoland vblwait->reply.tval_usec = now.tv_usec; 470182080Srnoland vblwait->reply.sequence = drm_vblank_count(dev, crtc); 471190401Srnoland DRM_DEBUG("returning %d to client, irq_enabled %d\n", 472190401Srnoland vblwait->reply.sequence, dev->irq_enabled); 473189050Srnoland } else { 474189050Srnoland DRM_DEBUG("vblank wait interrupted by signal\n"); 475182080Srnoland } 476145132Sanholt } 477145132Sanholt 478182080Srnolanddone: 479194963Srnoland DRM_SPINLOCK(&dev->vbl_lock); 480182080Srnoland drm_vblank_put(dev, crtc); 481194963Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 482194963Srnoland 483145132Sanholt return ret; 484145132Sanholt} 485145132Sanholt 486182080Srnolandvoid drm_handle_vblank(struct drm_device *dev, int crtc) 487182080Srnoland{ 488194963Srnoland atomic_add_rel_32(&dev->vblank[crtc].count, 1); 489182080Srnoland DRM_WAKEUP(&dev->vblank[crtc].queue); 490182080Srnoland} 491182080Srnoland 492