drm_irq.c revision 183833
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 183833 2008-10-13 18:03:27Z 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 39182080Srnolandstatic void drm_locked_task(void *context, int pending __unused); 40182080Srnoland 41182080Srnolandint drm_irq_by_busid(struct drm_device *dev, void *data, 42182080Srnoland struct drm_file *file_priv) 43145132Sanholt{ 44183573Srnoland struct drm_irq_busid *irq = data; 45145132Sanholt 46182080Srnoland if ((irq->busnum >> 8) != dev->pci_domain || 47182080Srnoland (irq->busnum & 0xff) != dev->pci_bus || 48182080Srnoland irq->devnum != dev->pci_slot || 49182080Srnoland irq->funcnum != dev->pci_func) 50145132Sanholt return EINVAL; 51145132Sanholt 52182080Srnoland irq->irq = dev->irq; 53145132Sanholt 54145132Sanholt DRM_DEBUG("%d:%d:%d => IRQ %d\n", 55183573Srnoland irq->busnum, irq->devnum, irq->funcnum, irq->irq); 56145132Sanholt 57145132Sanholt return 0; 58145132Sanholt} 59145132Sanholt 60145132Sanholtstatic irqreturn_t 61145132Sanholtdrm_irq_handler_wrap(DRM_IRQ_ARGS) 62145132Sanholt{ 63182080Srnoland struct drm_device *dev = arg; 64145132Sanholt 65145132Sanholt DRM_SPINLOCK(&dev->irq_lock); 66183573Srnoland dev->driver->irq_handler(arg); 67145132Sanholt DRM_SPINUNLOCK(&dev->irq_lock); 68145132Sanholt} 69145132Sanholt 70182080Srnolandstatic void vblank_disable_fn(void *arg) 71145132Sanholt{ 72182080Srnoland struct drm_device *dev = (struct drm_device *)arg; 73182080Srnoland int i; 74182080Srnoland 75182080Srnoland if (callout_pending(&dev->vblank_disable_timer)) { 76182080Srnoland /* callout was reset */ 77182080Srnoland return; 78182080Srnoland } 79182080Srnoland if (!callout_active(&dev->vblank_disable_timer)) { 80182080Srnoland /* callout was stopped */ 81182080Srnoland return; 82182080Srnoland } 83182080Srnoland callout_deactivate(&dev->vblank_disable_timer); 84182080Srnoland 85183573Srnoland DRM_DEBUG("vblank_disable_allowed=%d\n", dev->vblank_disable_allowed); 86182080Srnoland if (!dev->vblank_disable_allowed) 87182080Srnoland return; 88182080Srnoland 89182080Srnoland for (i = 0; i < dev->num_crtcs; i++) { 90182080Srnoland if (atomic_read(&dev->vblank[i].refcount) == 0 && 91182080Srnoland dev->vblank[i].enabled) { 92182080Srnoland DRM_DEBUG("disabling vblank on crtc %d\n", i); 93182080Srnoland dev->vblank[i].last = 94183573Srnoland dev->driver->get_vblank_counter(dev, i); 95183573Srnoland dev->driver->disable_vblank(dev, i); 96182080Srnoland dev->vblank[i].enabled = 0; 97182080Srnoland } 98182080Srnoland } 99182080Srnoland} 100182080Srnoland 101182080Srnolandstatic void drm_vblank_cleanup(struct drm_device *dev) 102182080Srnoland{ 103182080Srnoland unsigned long irqflags; 104182080Srnoland 105182080Srnoland /* Bail if the driver didn't call drm_vblank_init() */ 106182080Srnoland if (dev->num_crtcs == 0) 107183573Srnoland return; 108182080Srnoland 109182080Srnoland DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); 110182080Srnoland callout_stop(&dev->vblank_disable_timer); 111182080Srnoland DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); 112182080Srnoland 113182080Srnoland callout_drain(&dev->vblank_disable_timer); 114182080Srnoland 115182080Srnoland vblank_disable_fn((void *)dev); 116182080Srnoland 117183833Srnoland free(dev->vblank, DRM_MEM_DRIVER); 118182080Srnoland 119182080Srnoland dev->num_crtcs = 0; 120182080Srnoland} 121182080Srnoland 122182080Srnolandint drm_vblank_init(struct drm_device *dev, int num_crtcs) 123182080Srnoland{ 124182080Srnoland int i, ret = ENOMEM; 125182080Srnoland 126182080Srnoland callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); 127182080Srnoland atomic_set(&dev->vbl_signal_pending, 0); 128182080Srnoland dev->num_crtcs = num_crtcs; 129182080Srnoland 130183833Srnoland dev->vblank = malloc(sizeof(struct drm_vblank_info) * num_crtcs, 131183833Srnoland DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 132182080Srnoland if (!dev->vblank) 133182080Srnoland goto err; 134182080Srnoland 135183573Srnoland DRM_DEBUG("\n"); 136183573Srnoland 137182080Srnoland /* Zero per-crtc vblank stuff */ 138182080Srnoland for (i = 0; i < num_crtcs; i++) { 139182080Srnoland DRM_INIT_WAITQUEUE(&dev->vblank[i].queue); 140182080Srnoland TAILQ_INIT(&dev->vblank[i].sigs); 141182080Srnoland atomic_set(&dev->vblank[i].count, 0); 142182080Srnoland atomic_set(&dev->vblank[i].refcount, 0); 143182080Srnoland } 144182080Srnoland 145182080Srnoland dev->vblank_disable_allowed = 0; 146182080Srnoland 147182080Srnoland return 0; 148182080Srnoland 149182080Srnolanderr: 150182080Srnoland drm_vblank_cleanup(dev); 151182080Srnoland return ret; 152182080Srnoland} 153182080Srnoland 154182080Srnolandint drm_irq_install(struct drm_device *dev) 155182080Srnoland{ 156145132Sanholt int retcode; 157145132Sanholt 158145132Sanholt if (dev->irq == 0 || dev->dev_private == NULL) 159182080Srnoland return EINVAL; 160145132Sanholt 161183573Srnoland DRM_DEBUG("irq=%d\n", dev->irq); 162145132Sanholt 163145132Sanholt DRM_LOCK(); 164145132Sanholt if (dev->irq_enabled) { 165145132Sanholt DRM_UNLOCK(); 166182080Srnoland return EBUSY; 167145132Sanholt } 168145132Sanholt dev->irq_enabled = 1; 169145132Sanholt 170145132Sanholt dev->context_flag = 0; 171145132Sanholt 172183573Srnoland /* Before installing handler */ 173183573Srnoland dev->driver->irq_preinstall(dev); 174145132Sanholt DRM_UNLOCK(); 175145132Sanholt 176183573Srnoland /* Install handler */ 177145132Sanholt dev->irqrid = 0; 178145132Sanholt dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ, 179145132Sanholt &dev->irqrid, RF_SHAREABLE); 180145132Sanholt if (!dev->irqr) { 181145132Sanholt retcode = ENOENT; 182145132Sanholt goto err; 183145132Sanholt } 184182080Srnoland#if __FreeBSD_version >= 700031 185182080Srnoland retcode = bus_setup_intr(dev->device, dev->irqr, 186182080Srnoland INTR_TYPE_TTY | INTR_MPSAFE, 187182080Srnoland NULL, drm_irq_handler_wrap, dev, &dev->irqh); 188145132Sanholt#else 189182080Srnoland retcode = bus_setup_intr(dev->device, dev->irqr, 190182080Srnoland INTR_TYPE_TTY | INTR_MPSAFE, 191182080Srnoland drm_irq_handler_wrap, dev, &dev->irqh); 192145132Sanholt#endif 193145132Sanholt if (retcode != 0) 194145132Sanholt goto err; 195145132Sanholt 196183573Srnoland /* After installing handler */ 197145132Sanholt DRM_LOCK(); 198183573Srnoland dev->driver->irq_postinstall(dev); 199145132Sanholt DRM_UNLOCK(); 200145132Sanholt 201182080Srnoland TASK_INIT(&dev->locked_task, 0, drm_locked_task, dev); 202145132Sanholt return 0; 203145132Sanholterr: 204145132Sanholt DRM_LOCK(); 205145132Sanholt dev->irq_enabled = 0; 206145132Sanholt if (dev->irqrid != 0) { 207145132Sanholt bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, 208145132Sanholt dev->irqr); 209145132Sanholt dev->irqrid = 0; 210145132Sanholt } 211145132Sanholt DRM_UNLOCK(); 212145132Sanholt return retcode; 213145132Sanholt} 214145132Sanholt 215182080Srnolandint drm_irq_uninstall(struct drm_device *dev) 216145132Sanholt{ 217145132Sanholt int irqrid; 218145132Sanholt 219145132Sanholt if (!dev->irq_enabled) 220182080Srnoland return EINVAL; 221145132Sanholt 222145132Sanholt dev->irq_enabled = 0; 223145132Sanholt irqrid = dev->irqrid; 224145132Sanholt dev->irqrid = 0; 225145132Sanholt 226183573Srnoland DRM_DEBUG("irq=%d\n", dev->irq); 227145132Sanholt 228183573Srnoland dev->driver->irq_uninstall(dev); 229145132Sanholt 230145132Sanholt DRM_UNLOCK(); 231145132Sanholt bus_teardown_intr(dev->device, dev->irqr, dev->irqh); 232145132Sanholt bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr); 233145132Sanholt DRM_LOCK(); 234183573Srnoland 235182080Srnoland drm_vblank_cleanup(dev); 236145132Sanholt 237145132Sanholt return 0; 238145132Sanholt} 239145132Sanholt 240182080Srnolandint drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) 241145132Sanholt{ 242183573Srnoland struct drm_control *ctl = data; 243145132Sanholt int err; 244145132Sanholt 245183573Srnoland switch (ctl->func) { 246145132Sanholt case DRM_INST_HANDLER: 247145132Sanholt /* Handle drivers whose DRM used to require IRQ setup but the 248145132Sanholt * no longer does. 249145132Sanholt */ 250183573Srnoland if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 251145132Sanholt return 0; 252145132Sanholt if (dev->if_version < DRM_IF_VERSION(1, 2) && 253182080Srnoland ctl->irq != dev->irq) 254182080Srnoland return EINVAL; 255145132Sanholt return drm_irq_install(dev); 256145132Sanholt case DRM_UNINST_HANDLER: 257183573Srnoland if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 258145132Sanholt return 0; 259145132Sanholt DRM_LOCK(); 260145132Sanholt err = drm_irq_uninstall(dev); 261145132Sanholt DRM_UNLOCK(); 262145132Sanholt return err; 263145132Sanholt default: 264182080Srnoland return EINVAL; 265145132Sanholt } 266145132Sanholt} 267145132Sanholt 268182080Srnolandu32 drm_vblank_count(struct drm_device *dev, int crtc) 269145132Sanholt{ 270182080Srnoland return atomic_read(&dev->vblank[crtc].count); 271182080Srnoland} 272145132Sanholt 273182080Srnolandstatic void drm_update_vblank_count(struct drm_device *dev, int crtc) 274182080Srnoland{ 275182080Srnoland u32 cur_vblank, diff; 276182080Srnoland 277182080Srnoland /* 278182080Srnoland * Interrupts were disabled prior to this call, so deal with counter 279182080Srnoland * wrap if needed. 280182080Srnoland * NOTE! It's possible we lost a full dev->max_vblank_count events 281182080Srnoland * here if the register is small or we had vblank interrupts off for 282182080Srnoland * a long time. 283182080Srnoland */ 284183573Srnoland cur_vblank = dev->driver->get_vblank_counter(dev, crtc); 285182080Srnoland diff = cur_vblank - dev->vblank[crtc].last; 286182080Srnoland if (cur_vblank < dev->vblank[crtc].last) { 287182080Srnoland diff += dev->max_vblank_count; 288182080Srnoland 289183573Srnoland DRM_DEBUG("vblank[%d].last=0x%x, cur_vblank=0x%x => diff=0x%x\n", 290182080Srnoland crtc, dev->vblank[crtc].last, cur_vblank, diff); 291182080Srnoland } 292182080Srnoland 293182080Srnoland DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", 294182080Srnoland crtc, diff); 295182080Srnoland 296182080Srnoland atomic_add(diff, &dev->vblank[crtc].count); 297182080Srnoland} 298182080Srnoland 299182080Srnolandint drm_vblank_get(struct drm_device *dev, int crtc) 300182080Srnoland{ 301182080Srnoland unsigned long irqflags; 302182080Srnoland int ret = 0; 303182080Srnoland 304182080Srnoland DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); 305182080Srnoland /* Going from 0->1 means we have to enable interrupts again */ 306182080Srnoland atomic_add_acq_int(&dev->vblank[crtc].refcount, 1); 307182080Srnoland if (dev->vblank[crtc].refcount == 1 && 308182080Srnoland !dev->vblank[crtc].enabled) { 309183573Srnoland ret = dev->driver->enable_vblank(dev, crtc); 310182080Srnoland if (ret) 311182080Srnoland atomic_dec(&dev->vblank[crtc].refcount); 312182080Srnoland else { 313182080Srnoland dev->vblank[crtc].enabled = 1; 314182080Srnoland drm_update_vblank_count(dev, crtc); 315182080Srnoland } 316182080Srnoland } 317182080Srnoland DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); 318182080Srnoland 319182080Srnoland return ret; 320182080Srnoland} 321182080Srnoland 322182080Srnolandvoid drm_vblank_put(struct drm_device *dev, int crtc) 323182080Srnoland{ 324182080Srnoland unsigned long irqflags; 325182080Srnoland 326182080Srnoland DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); 327182080Srnoland /* Last user schedules interrupt disable */ 328182080Srnoland atomic_subtract_acq_int(&dev->vblank[crtc].refcount, 1); 329182080Srnoland if (dev->vblank[crtc].refcount == 0) 330182080Srnoland callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, 331182080Srnoland (timeout_t *)vblank_disable_fn, (void *)dev); 332182080Srnoland DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); 333182080Srnoland} 334182080Srnoland 335182080Srnolandint drm_modeset_ctl(struct drm_device *dev, void *data, 336182080Srnoland struct drm_file *file_priv) 337182080Srnoland{ 338182080Srnoland struct drm_modeset_ctl *modeset = data; 339182080Srnoland unsigned long irqflags; 340182080Srnoland int crtc, ret = 0; 341182080Srnoland 342183573Srnoland DRM_DEBUG("num_crtcs=%d\n", dev->num_crtcs); 343182080Srnoland /* If drm_vblank_init() hasn't been called yet, just no-op */ 344182080Srnoland if (!dev->num_crtcs) 345183573Srnoland goto out; 346182080Srnoland 347182080Srnoland crtc = modeset->crtc; 348183573Srnoland DRM_DEBUG("crtc=%d\n", crtc); 349182080Srnoland if (crtc >= dev->num_crtcs) { 350182080Srnoland ret = EINVAL; 351182080Srnoland goto out; 352182080Srnoland } 353182080Srnoland 354182080Srnoland /* 355182080Srnoland * To avoid all the problems that might happen if interrupts 356182080Srnoland * were enabled/disabled around or between these calls, we just 357182080Srnoland * have the kernel take a reference on the CRTC (just once though 358182080Srnoland * to avoid corrupting the count if multiple, mismatch calls occur), 359182080Srnoland * so that interrupts remain enabled in the interim. 360182080Srnoland */ 361182080Srnoland switch (modeset->cmd) { 362182080Srnoland case _DRM_PRE_MODESET: 363183573Srnoland DRM_DEBUG("pre-modeset\n"); 364182080Srnoland if (!dev->vblank[crtc].inmodeset) { 365182080Srnoland dev->vblank[crtc].inmodeset = 1; 366182080Srnoland drm_vblank_get(dev, crtc); 367182080Srnoland } 368182080Srnoland break; 369182080Srnoland case _DRM_POST_MODESET: 370183573Srnoland DRM_DEBUG("post-modeset\n"); 371182080Srnoland if (dev->vblank[crtc].inmodeset) { 372182080Srnoland DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); 373182080Srnoland dev->vblank_disable_allowed = 1; 374182080Srnoland dev->vblank[crtc].inmodeset = 0; 375182080Srnoland DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); 376182080Srnoland drm_vblank_put(dev, crtc); 377182080Srnoland } 378182080Srnoland break; 379182080Srnoland default: 380182080Srnoland ret = EINVAL; 381182080Srnoland break; 382182080Srnoland } 383182080Srnoland 384182080Srnolandout: 385182080Srnoland return ret; 386182080Srnoland} 387182080Srnoland 388182080Srnolandint drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) 389182080Srnoland{ 390183573Srnoland union drm_wait_vblank *vblwait = data; 391182080Srnoland int ret = 0; 392182080Srnoland int flags, seq, crtc; 393182080Srnoland 394145132Sanholt if (!dev->irq_enabled) 395182080Srnoland return EINVAL; 396145132Sanholt 397182080Srnoland if (vblwait->request.type & 398182080Srnoland ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { 399182080Srnoland DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", 400182080Srnoland vblwait->request.type, 401182080Srnoland (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); 402182080Srnoland return EINVAL; 403182080Srnoland } 404145132Sanholt 405182080Srnoland flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 406182080Srnoland crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 407182080Srnoland 408182080Srnoland if (crtc >= dev->num_crtcs) 409182080Srnoland return EINVAL; 410182080Srnoland 411182080Srnoland ret = drm_vblank_get(dev, crtc); 412182080Srnoland if (ret) 413183573Srnoland return ret; 414182080Srnoland seq = drm_vblank_count(dev, crtc); 415182080Srnoland 416182080Srnoland switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 417182080Srnoland case _DRM_VBLANK_RELATIVE: 418182080Srnoland vblwait->request.sequence += seq; 419182080Srnoland vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 420182080Srnoland case _DRM_VBLANK_ABSOLUTE: 421182080Srnoland break; 422182080Srnoland default: 423182080Srnoland ret = EINVAL; 424182080Srnoland goto done; 425145132Sanholt } 426145132Sanholt 427182080Srnoland if ((flags & _DRM_VBLANK_NEXTONMISS) && 428182080Srnoland (seq - vblwait->request.sequence) <= (1<<23)) { 429182080Srnoland vblwait->request.sequence = seq + 1; 430182080Srnoland } 431182080Srnoland 432145132Sanholt if (flags & _DRM_VBLANK_SIGNAL) { 433145132Sanholt#if 0 /* disabled */ 434183833Srnoland drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), 435183833Srnoland DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); 436145132Sanholt if (vbl_sig == NULL) 437145132Sanholt return ENOMEM; 438145132Sanholt 439182080Srnoland vbl_sig->sequence = vblwait->request.sequence; 440182080Srnoland vbl_sig->signo = vblwait->request.signal; 441145132Sanholt vbl_sig->pid = DRM_CURRENTPID; 442145132Sanholt 443182080Srnoland vblwait->reply.sequence = atomic_read(&dev->vbl_received); 444145132Sanholt 445182080Srnoland DRM_SPINLOCK(&dev->vbl_lock); 446145132Sanholt TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link); 447182080Srnoland DRM_SPINUNLOCK(&dev->vbl_lock); 448145132Sanholt ret = 0; 449145132Sanholt#endif 450145132Sanholt ret = EINVAL; 451145132Sanholt } else { 452145132Sanholt DRM_LOCK(); 453182080Srnoland /* shared code returns -errno */ 454182080Srnoland 455182080Srnoland DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * DRM_HZ, 456182080Srnoland ((drm_vblank_count(dev, crtc) 457182080Srnoland - vblwait->request.sequence) <= (1 << 23))); 458145132Sanholt DRM_UNLOCK(); 459145132Sanholt 460182080Srnoland if (ret != EINTR) { 461182080Srnoland struct timeval now; 462182080Srnoland 463182080Srnoland microtime(&now); 464182080Srnoland vblwait->reply.tval_sec = now.tv_sec; 465182080Srnoland vblwait->reply.tval_usec = now.tv_usec; 466182080Srnoland vblwait->reply.sequence = drm_vblank_count(dev, crtc); 467182080Srnoland } 468145132Sanholt } 469145132Sanholt 470182080Srnolanddone: 471182080Srnoland drm_vblank_put(dev, crtc); 472145132Sanholt return ret; 473145132Sanholt} 474145132Sanholt 475182080Srnolandvoid drm_vbl_send_signals(struct drm_device *dev, int crtc) 476145132Sanholt{ 477145132Sanholt} 478145132Sanholt 479145132Sanholt#if 0 /* disabled */ 480182080Srnolandvoid drm_vbl_send_signals(struct drm_device *dev, int crtc ) 481145132Sanholt{ 482145132Sanholt drm_vbl_sig_t *vbl_sig; 483145132Sanholt unsigned int vbl_seq = atomic_read( &dev->vbl_received ); 484145132Sanholt struct proc *p; 485145132Sanholt 486145132Sanholt vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list); 487145132Sanholt while (vbl_sig != NULL) { 488145132Sanholt drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link); 489145132Sanholt 490183573Srnoland if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { 491145132Sanholt p = pfind(vbl_sig->pid); 492145132Sanholt if (p != NULL) 493145132Sanholt psignal(p, vbl_sig->signo); 494145132Sanholt 495145132Sanholt TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link); 496145132Sanholt DRM_FREE(vbl_sig,sizeof(*vbl_sig)); 497145132Sanholt } 498145132Sanholt vbl_sig = next; 499145132Sanholt } 500145132Sanholt} 501145132Sanholt#endif 502182080Srnoland 503182080Srnolandvoid drm_handle_vblank(struct drm_device *dev, int crtc) 504182080Srnoland{ 505182080Srnoland atomic_inc(&dev->vblank[crtc].count); 506182080Srnoland DRM_WAKEUP(&dev->vblank[crtc].queue); 507182080Srnoland drm_vbl_send_signals(dev, crtc); 508182080Srnoland} 509182080Srnoland 510182080Srnolandstatic void drm_locked_task(void *context, int pending __unused) 511182080Srnoland{ 512182080Srnoland struct drm_device *dev = context; 513182080Srnoland 514182080Srnoland DRM_SPINLOCK(&dev->tsk_lock); 515182080Srnoland 516182080Srnoland DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */ 517182080Srnoland if (dev->locked_task_call == NULL || 518183573Srnoland drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT) == 0) { 519182080Srnoland DRM_UNLOCK(); 520182080Srnoland DRM_SPINUNLOCK(&dev->tsk_lock); 521182080Srnoland return; 522182080Srnoland } 523182080Srnoland 524182080Srnoland dev->lock.file_priv = NULL; /* kernel owned */ 525182080Srnoland dev->lock.lock_time = jiffies; 526182080Srnoland atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); 527182080Srnoland 528182080Srnoland DRM_UNLOCK(); 529182080Srnoland 530182080Srnoland dev->locked_task_call(dev); 531182080Srnoland 532183573Srnoland drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT); 533182080Srnoland 534182080Srnoland dev->locked_task_call = NULL; 535182080Srnoland 536182080Srnoland DRM_SPINUNLOCK(&dev->tsk_lock); 537182080Srnoland} 538182080Srnoland 539182080Srnolandvoid 540182080Srnolanddrm_locked_tasklet(struct drm_device *dev, 541182080Srnoland void (*tasklet)(struct drm_device *dev)) 542182080Srnoland{ 543182080Srnoland DRM_SPINLOCK(&dev->tsk_lock); 544182080Srnoland if (dev->locked_task_call != NULL) { 545182080Srnoland DRM_SPINUNLOCK(&dev->tsk_lock); 546182080Srnoland return; 547182080Srnoland } 548182080Srnoland 549182080Srnoland dev->locked_task_call = tasklet; 550182080Srnoland DRM_SPINUNLOCK(&dev->tsk_lock); 551182080Srnoland taskqueue_enqueue(taskqueue_swi, &dev->locked_task); 552182080Srnoland} 553