drm_irq.c revision 190433
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: head/sys/dev/drm/drm_irq.c 190433 2009-03-26 02:10:18Z rnoland $"); 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 73182080Srnoland if (callout_pending(&dev->vblank_disable_timer)) { 74182080Srnoland /* callout was reset */ 75182080Srnoland return; 76182080Srnoland } 77182080Srnoland if (!callout_active(&dev->vblank_disable_timer)) { 78182080Srnoland /* callout was stopped */ 79182080Srnoland return; 80182080Srnoland } 81182080Srnoland callout_deactivate(&dev->vblank_disable_timer); 82182080Srnoland 83190401Srnoland DRM_DEBUG("vblank_disable: %s\n", dev->vblank_disable_allowed ? 84190401Srnoland "allowed" : "denied"); 85182080Srnoland if (!dev->vblank_disable_allowed) 86182080Srnoland return; 87182080Srnoland 88182080Srnoland for (i = 0; i < dev->num_crtcs; i++) { 89182080Srnoland if (atomic_read(&dev->vblank[i].refcount) == 0 && 90190401Srnoland dev->vblank[i].enabled && !dev->vblank[i].inmodeset) { 91182080Srnoland DRM_DEBUG("disabling vblank on crtc %d\n", i); 92182080Srnoland dev->vblank[i].last = 93183573Srnoland dev->driver->get_vblank_counter(dev, i); 94183573Srnoland dev->driver->disable_vblank(dev, i); 95182080Srnoland dev->vblank[i].enabled = 0; 96182080Srnoland } 97182080Srnoland } 98182080Srnoland} 99182080Srnoland 100189130Srnolandvoid drm_vblank_cleanup(struct drm_device *dev) 101182080Srnoland{ 102182080Srnoland /* Bail if the driver didn't call drm_vblank_init() */ 103182080Srnoland if (dev->num_crtcs == 0) 104183573Srnoland return; 105182080Srnoland 106190022Srnoland DRM_SPINLOCK(&dev->vbl_lock); 107182080Srnoland callout_stop(&dev->vblank_disable_timer); 108190022Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 109182080Srnoland 110182080Srnoland callout_drain(&dev->vblank_disable_timer); 111182080Srnoland 112182080Srnoland vblank_disable_fn((void *)dev); 113182080Srnoland 114183833Srnoland free(dev->vblank, DRM_MEM_DRIVER); 115182080Srnoland 116182080Srnoland dev->num_crtcs = 0; 117182080Srnoland} 118182080Srnoland 119182080Srnolandint drm_vblank_init(struct drm_device *dev, int num_crtcs) 120182080Srnoland{ 121182080Srnoland int i, ret = ENOMEM; 122182080Srnoland 123182080Srnoland callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); 124182080Srnoland atomic_set(&dev->vbl_signal_pending, 0); 125182080Srnoland dev->num_crtcs = num_crtcs; 126182080Srnoland 127183833Srnoland dev->vblank = malloc(sizeof(struct drm_vblank_info) * num_crtcs, 128183833Srnoland DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 129182080Srnoland if (!dev->vblank) 130182080Srnoland goto err; 131182080Srnoland 132183573Srnoland DRM_DEBUG("\n"); 133183573Srnoland 134182080Srnoland /* Zero per-crtc vblank stuff */ 135182080Srnoland for (i = 0; i < num_crtcs; i++) { 136182080Srnoland DRM_INIT_WAITQUEUE(&dev->vblank[i].queue); 137182080Srnoland TAILQ_INIT(&dev->vblank[i].sigs); 138182080Srnoland atomic_set(&dev->vblank[i].count, 0); 139182080Srnoland atomic_set(&dev->vblank[i].refcount, 0); 140182080Srnoland } 141182080Srnoland 142182080Srnoland dev->vblank_disable_allowed = 0; 143182080Srnoland 144182080Srnoland return 0; 145182080Srnoland 146182080Srnolanderr: 147182080Srnoland drm_vblank_cleanup(dev); 148182080Srnoland return ret; 149182080Srnoland} 150182080Srnoland 151182080Srnolandint drm_irq_install(struct drm_device *dev) 152182080Srnoland{ 153190401Srnoland int crtc, retcode; 154145132Sanholt 155145132Sanholt if (dev->irq == 0 || dev->dev_private == NULL) 156182080Srnoland return EINVAL; 157145132Sanholt 158183573Srnoland DRM_DEBUG("irq=%d\n", dev->irq); 159145132Sanholt 160145132Sanholt DRM_LOCK(); 161145132Sanholt if (dev->irq_enabled) { 162145132Sanholt DRM_UNLOCK(); 163182080Srnoland return EBUSY; 164145132Sanholt } 165145132Sanholt dev->irq_enabled = 1; 166145132Sanholt 167145132Sanholt dev->context_flag = 0; 168145132Sanholt 169183573Srnoland /* Before installing handler */ 170183573Srnoland dev->driver->irq_preinstall(dev); 171145132Sanholt DRM_UNLOCK(); 172145132Sanholt 173183573Srnoland /* Install handler */ 174182080Srnoland#if __FreeBSD_version >= 700031 175182080Srnoland retcode = bus_setup_intr(dev->device, dev->irqr, 176182080Srnoland INTR_TYPE_TTY | INTR_MPSAFE, 177182080Srnoland NULL, drm_irq_handler_wrap, dev, &dev->irqh); 178145132Sanholt#else 179182080Srnoland retcode = bus_setup_intr(dev->device, dev->irqr, 180182080Srnoland INTR_TYPE_TTY | INTR_MPSAFE, 181182080Srnoland drm_irq_handler_wrap, dev, &dev->irqh); 182145132Sanholt#endif 183145132Sanholt if (retcode != 0) 184145132Sanholt goto err; 185145132Sanholt 186183573Srnoland /* After installing handler */ 187145132Sanholt DRM_LOCK(); 188183573Srnoland dev->driver->irq_postinstall(dev); 189145132Sanholt DRM_UNLOCK(); 190190401Srnoland if (dev->driver->enable_vblank) { 191190401Srnoland DRM_SPINLOCK(&dev->vbl_lock); 192190401Srnoland for( crtc = 0 ; crtc < dev->num_crtcs ; crtc++) { 193190401Srnoland if (dev->driver->enable_vblank(dev, crtc) == 0) { 194190401Srnoland dev->vblank[crtc].enabled = 1; 195190401Srnoland } 196190401Srnoland } 197190401Srnoland callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, 198190401Srnoland (timeout_t *)vblank_disable_fn, (void *)dev); 199190401Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 200190401Srnoland } 201145132Sanholt 202145132Sanholt return 0; 203145132Sanholterr: 204145132Sanholt DRM_LOCK(); 205145132Sanholt dev->irq_enabled = 0; 206145132Sanholt DRM_UNLOCK(); 207189052Srnoland 208145132Sanholt return retcode; 209145132Sanholt} 210145132Sanholt 211182080Srnolandint drm_irq_uninstall(struct drm_device *dev) 212145132Sanholt{ 213190022Srnoland int crtc; 214190022Srnoland 215145132Sanholt if (!dev->irq_enabled) 216182080Srnoland return EINVAL; 217145132Sanholt 218145132Sanholt dev->irq_enabled = 0; 219145132Sanholt 220190022Srnoland /* 221190022Srnoland * Wake up any waiters so they don't hang. 222190022Srnoland */ 223190022Srnoland DRM_SPINLOCK(&dev->vbl_lock); 224190022Srnoland for (crtc = 0; crtc < dev->num_crtcs; crtc++) { 225190125Srnoland if (dev->vblank[crtc].enabled) { 226190125Srnoland DRM_WAKEUP(&dev->vblank[crtc].queue); 227190401Srnoland dev->vblank[crtc].last = 228190401Srnoland dev->driver->get_vblank_counter(dev, crtc); 229190125Srnoland dev->vblank[crtc].enabled = 0; 230190125Srnoland } 231190022Srnoland } 232190022Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 233190022Srnoland 234183573Srnoland DRM_DEBUG("irq=%d\n", dev->irq); 235145132Sanholt 236183573Srnoland dev->driver->irq_uninstall(dev); 237145132Sanholt 238145132Sanholt DRM_UNLOCK(); 239145132Sanholt bus_teardown_intr(dev->device, dev->irqr, dev->irqh); 240145132Sanholt DRM_LOCK(); 241183573Srnoland 242145132Sanholt return 0; 243145132Sanholt} 244145132Sanholt 245182080Srnolandint drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) 246145132Sanholt{ 247183573Srnoland struct drm_control *ctl = data; 248145132Sanholt int err; 249145132Sanholt 250183573Srnoland switch (ctl->func) { 251145132Sanholt case DRM_INST_HANDLER: 252145132Sanholt /* Handle drivers whose DRM used to require IRQ setup but the 253145132Sanholt * no longer does. 254145132Sanholt */ 255183573Srnoland if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 256145132Sanholt return 0; 257145132Sanholt if (dev->if_version < DRM_IF_VERSION(1, 2) && 258182080Srnoland ctl->irq != dev->irq) 259182080Srnoland return EINVAL; 260145132Sanholt return drm_irq_install(dev); 261145132Sanholt case DRM_UNINST_HANDLER: 262183573Srnoland if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 263145132Sanholt return 0; 264145132Sanholt DRM_LOCK(); 265145132Sanholt err = drm_irq_uninstall(dev); 266145132Sanholt DRM_UNLOCK(); 267145132Sanholt return err; 268145132Sanholt default: 269182080Srnoland return EINVAL; 270145132Sanholt } 271145132Sanholt} 272145132Sanholt 273182080Srnolandu32 drm_vblank_count(struct drm_device *dev, int crtc) 274145132Sanholt{ 275182080Srnoland return atomic_read(&dev->vblank[crtc].count); 276182080Srnoland} 277145132Sanholt 278182080Srnolandstatic void drm_update_vblank_count(struct drm_device *dev, int crtc) 279182080Srnoland{ 280182080Srnoland u32 cur_vblank, diff; 281182080Srnoland 282182080Srnoland /* 283182080Srnoland * Interrupts were disabled prior to this call, so deal with counter 284182080Srnoland * wrap if needed. 285182080Srnoland * NOTE! It's possible we lost a full dev->max_vblank_count events 286182080Srnoland * here if the register is small or we had vblank interrupts off for 287182080Srnoland * a long time. 288182080Srnoland */ 289183573Srnoland cur_vblank = dev->driver->get_vblank_counter(dev, crtc); 290182080Srnoland diff = cur_vblank - dev->vblank[crtc].last; 291182080Srnoland if (cur_vblank < dev->vblank[crtc].last) { 292182080Srnoland diff += dev->max_vblank_count; 293182080Srnoland 294183573Srnoland DRM_DEBUG("vblank[%d].last=0x%x, cur_vblank=0x%x => diff=0x%x\n", 295182080Srnoland crtc, dev->vblank[crtc].last, cur_vblank, diff); 296182080Srnoland } 297182080Srnoland 298182080Srnoland DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", 299182080Srnoland crtc, diff); 300182080Srnoland 301182080Srnoland atomic_add(diff, &dev->vblank[crtc].count); 302182080Srnoland} 303182080Srnoland 304182080Srnolandint drm_vblank_get(struct drm_device *dev, int crtc) 305182080Srnoland{ 306182080Srnoland int ret = 0; 307182080Srnoland 308190022Srnoland DRM_SPINLOCK(&dev->vbl_lock); 309182080Srnoland /* Going from 0->1 means we have to enable interrupts again */ 310182080Srnoland atomic_add_acq_int(&dev->vblank[crtc].refcount, 1); 311182080Srnoland if (dev->vblank[crtc].refcount == 1 && 312182080Srnoland !dev->vblank[crtc].enabled) { 313183573Srnoland ret = dev->driver->enable_vblank(dev, crtc); 314190022Srnoland DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); 315182080Srnoland if (ret) 316182080Srnoland atomic_dec(&dev->vblank[crtc].refcount); 317182080Srnoland else { 318182080Srnoland dev->vblank[crtc].enabled = 1; 319182080Srnoland drm_update_vblank_count(dev, crtc); 320182080Srnoland } 321182080Srnoland } 322190022Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 323182080Srnoland 324182080Srnoland return ret; 325182080Srnoland} 326182080Srnoland 327182080Srnolandvoid drm_vblank_put(struct drm_device *dev, int crtc) 328182080Srnoland{ 329190022Srnoland KASSERT(atomic_read(&dev->vblank[crtc].refcount) > 0, 330190022Srnoland ("invalid refcount")); 331182080Srnoland 332182080Srnoland /* Last user schedules interrupt disable */ 333182080Srnoland atomic_subtract_acq_int(&dev->vblank[crtc].refcount, 1); 334190022Srnoland 335190401Srnoland DRM_SPINLOCK(&dev->vbl_lock); 336182080Srnoland if (dev->vblank[crtc].refcount == 0) 337182080Srnoland callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, 338182080Srnoland (timeout_t *)vblank_disable_fn, (void *)dev); 339190401Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 340182080Srnoland} 341182080Srnoland 342182080Srnolandint drm_modeset_ctl(struct drm_device *dev, void *data, 343182080Srnoland struct drm_file *file_priv) 344182080Srnoland{ 345182080Srnoland struct drm_modeset_ctl *modeset = data; 346182080Srnoland int crtc, ret = 0; 347182080Srnoland 348183573Srnoland DRM_DEBUG("num_crtcs=%d\n", dev->num_crtcs); 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; 354183573Srnoland DRM_DEBUG("crtc=%d\n", crtc); 355182080Srnoland if (crtc >= dev->num_crtcs) { 356182080Srnoland ret = EINVAL; 357182080Srnoland goto out; 358182080Srnoland } 359182080Srnoland 360182080Srnoland /* 361182080Srnoland * To avoid all the problems that might happen if interrupts 362182080Srnoland * were enabled/disabled around or between these calls, we just 363182080Srnoland * have the kernel take a reference on the CRTC (just once though 364182080Srnoland * to avoid corrupting the count if multiple, mismatch calls occur), 365182080Srnoland * so that interrupts remain enabled in the interim. 366182080Srnoland */ 367182080Srnoland switch (modeset->cmd) { 368182080Srnoland case _DRM_PRE_MODESET: 369183573Srnoland DRM_DEBUG("pre-modeset\n"); 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 } 375182080Srnoland break; 376182080Srnoland case _DRM_POST_MODESET: 377183573Srnoland DRM_DEBUG("post-modeset\n"); 378182080Srnoland if (dev->vblank[crtc].inmodeset) { 379190022Srnoland DRM_SPINLOCK(&dev->vbl_lock); 380182080Srnoland dev->vblank_disable_allowed = 1; 381190022Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 382190022Srnoland 383190022Srnoland if (dev->vblank[crtc].inmodeset & 0x2) 384190022Srnoland drm_vblank_put(dev, crtc); 385190022Srnoland 386182080Srnoland dev->vblank[crtc].inmodeset = 0; 387182080Srnoland } 388182080Srnoland break; 389182080Srnoland default: 390182080Srnoland ret = EINVAL; 391182080Srnoland break; 392182080Srnoland } 393182080Srnoland 394182080Srnolandout: 395182080Srnoland return ret; 396182080Srnoland} 397182080Srnoland 398182080Srnolandint drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) 399182080Srnoland{ 400183573Srnoland union drm_wait_vblank *vblwait = data; 401189050Srnoland unsigned int flags, seq, crtc; 402182080Srnoland int ret = 0; 403182080Srnoland 404145132Sanholt if (!dev->irq_enabled) 405182080Srnoland return EINVAL; 406145132Sanholt 407182080Srnoland if (vblwait->request.type & 408182080Srnoland ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { 409182080Srnoland DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", 410182080Srnoland vblwait->request.type, 411182080Srnoland (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); 412182080Srnoland return EINVAL; 413182080Srnoland } 414145132Sanholt 415182080Srnoland flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 416182080Srnoland crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 417182080Srnoland 418182080Srnoland if (crtc >= dev->num_crtcs) 419182080Srnoland return EINVAL; 420182080Srnoland 421182080Srnoland ret = drm_vblank_get(dev, crtc); 422189050Srnoland if (ret) { 423189050Srnoland DRM_ERROR("failed to acquire vblank counter, %d\n", ret); 424183573Srnoland return ret; 425189050Srnoland } 426182080Srnoland seq = drm_vblank_count(dev, crtc); 427182080Srnoland 428182080Srnoland switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 429182080Srnoland case _DRM_VBLANK_RELATIVE: 430182080Srnoland vblwait->request.sequence += seq; 431182080Srnoland vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 432182080Srnoland case _DRM_VBLANK_ABSOLUTE: 433182080Srnoland break; 434182080Srnoland default: 435182080Srnoland ret = EINVAL; 436182080Srnoland goto done; 437145132Sanholt } 438145132Sanholt 439182080Srnoland if ((flags & _DRM_VBLANK_NEXTONMISS) && 440182080Srnoland (seq - vblwait->request.sequence) <= (1<<23)) { 441182080Srnoland vblwait->request.sequence = seq + 1; 442182080Srnoland } 443182080Srnoland 444145132Sanholt if (flags & _DRM_VBLANK_SIGNAL) { 445145132Sanholt#if 0 /* disabled */ 446183833Srnoland drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), 447183833Srnoland DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 448145132Sanholt if (vbl_sig == NULL) 449145132Sanholt return ENOMEM; 450145132Sanholt 451182080Srnoland vbl_sig->sequence = vblwait->request.sequence; 452182080Srnoland vbl_sig->signo = vblwait->request.signal; 453145132Sanholt vbl_sig->pid = DRM_CURRENTPID; 454145132Sanholt 455182080Srnoland vblwait->reply.sequence = atomic_read(&dev->vbl_received); 456145132Sanholt 457182080Srnoland DRM_SPINLOCK(&dev->vbl_lock); 458145132Sanholt TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link); 459182080Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 460145132Sanholt ret = 0; 461145132Sanholt#endif 462145132Sanholt ret = EINVAL; 463145132Sanholt } else { 464189050Srnoland DRM_DEBUG("waiting on vblank count %d, crtc %d\n", 465189050Srnoland vblwait->request.sequence, crtc); 466190401Srnoland dev->vblank[crtc].last = vblwait->request.sequence; 467190401Srnoland for ( ret = 0 ; !ret && !(((drm_vblank_count(dev, crtc) - 468190401Srnoland vblwait->request.sequence) <= (1 << 23)) || 469190401Srnoland !dev->irq_enabled) ; ) { 470190433Srnoland mtx_lock(&dev->irq_lock); 471190433Srnoland if (!(((drm_vblank_count(dev, crtc) - 472190433Srnoland vblwait->request.sequence) <= (1 << 23)) || 473190433Srnoland !dev->irq_enabled)) 474190433Srnoland ret = mtx_sleep(&dev->vblank[crtc].queue, 475190433Srnoland &dev->irq_lock, PCATCH, "vblwtq", 476190433Srnoland 3 * DRM_HZ); 477190433Srnoland mtx_unlock(&dev->irq_lock); 478189050Srnoland } 479182080Srnoland 480190401Srnoland if (ret != EINTR && ret != ERESTART) { 481182080Srnoland struct timeval now; 482182080Srnoland 483182080Srnoland microtime(&now); 484182080Srnoland vblwait->reply.tval_sec = now.tv_sec; 485182080Srnoland vblwait->reply.tval_usec = now.tv_usec; 486182080Srnoland vblwait->reply.sequence = drm_vblank_count(dev, crtc); 487190401Srnoland DRM_DEBUG("returning %d to client, irq_enabled %d\n", 488190401Srnoland vblwait->reply.sequence, dev->irq_enabled); 489189050Srnoland } else { 490189050Srnoland DRM_DEBUG("vblank wait interrupted by signal\n"); 491182080Srnoland } 492145132Sanholt } 493145132Sanholt 494182080Srnolanddone: 495182080Srnoland drm_vblank_put(dev, crtc); 496145132Sanholt return ret; 497145132Sanholt} 498145132Sanholt 499182080Srnolandvoid drm_vbl_send_signals(struct drm_device *dev, int crtc) 500145132Sanholt{ 501145132Sanholt} 502145132Sanholt 503145132Sanholt#if 0 /* disabled */ 504182080Srnolandvoid drm_vbl_send_signals(struct drm_device *dev, int crtc ) 505145132Sanholt{ 506145132Sanholt drm_vbl_sig_t *vbl_sig; 507145132Sanholt unsigned int vbl_seq = atomic_read( &dev->vbl_received ); 508145132Sanholt struct proc *p; 509145132Sanholt 510145132Sanholt vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list); 511145132Sanholt while (vbl_sig != NULL) { 512145132Sanholt drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link); 513145132Sanholt 514183573Srnoland if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { 515145132Sanholt p = pfind(vbl_sig->pid); 516145132Sanholt if (p != NULL) 517145132Sanholt psignal(p, vbl_sig->signo); 518145132Sanholt 519145132Sanholt TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link); 520145132Sanholt DRM_FREE(vbl_sig,sizeof(*vbl_sig)); 521145132Sanholt } 522145132Sanholt vbl_sig = next; 523145132Sanholt } 524145132Sanholt} 525145132Sanholt#endif 526182080Srnoland 527182080Srnolandvoid drm_handle_vblank(struct drm_device *dev, int crtc) 528182080Srnoland{ 529182080Srnoland atomic_inc(&dev->vblank[crtc].count); 530182080Srnoland DRM_WAKEUP(&dev->vblank[crtc].queue); 531182080Srnoland drm_vbl_send_signals(dev, crtc); 532182080Srnoland} 533182080Srnoland 534