1235783Skib/*- 2235783Skib * Copyright 2003 Eric Anholt 3235783Skib * All Rights Reserved. 4235783Skib * 5235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 6235783Skib * copy of this software and associated documentation files (the "Software"), 7235783Skib * to deal in the Software without restriction, including without limitation 8235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9235783Skib * and/or sell copies of the Software, and to permit persons to whom the 10235783Skib * Software is furnished to do so, subject to the following conditions: 11235783Skib * 12235783Skib * The above copyright notice and this permission notice (including the next 13235783Skib * paragraph) shall be included in all copies or substantial portions of the 14235783Skib * Software. 15235783Skib * 16235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19235783Skib * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20235783Skib * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21235783Skib * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22235783Skib * 23235783Skib * Authors: 24235783Skib * Eric Anholt <anholt@FreeBSD.org> 25235783Skib * 26235783Skib */ 27235783Skib 28235783Skib#include <sys/cdefs.h> 29235783Skib__FBSDID("$FreeBSD$"); 30235783Skib 31235783Skib/** @file drm_irq.c 32235783Skib * Support code for handling setup/teardown of interrupt handlers and 33235783Skib * handing interrupt handlers off to the drivers. 34235783Skib */ 35235783Skib 36235783Skib#include <dev/drm2/drmP.h> 37235783Skib#include <dev/drm2/drm.h> 38235783Skib 39235783SkibMALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data"); 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 56235783Skibint drm_irq_by_busid(struct drm_device *dev, void *data, 57235783Skib struct drm_file *file_priv) 58235783Skib{ 59235783Skib struct drm_irq_busid *irq = data; 60235783Skib 61235783Skib if ((irq->busnum >> 8) != dev->pci_domain || 62235783Skib (irq->busnum & 0xff) != dev->pci_bus || 63235783Skib irq->devnum != dev->pci_slot || 64235783Skib irq->funcnum != dev->pci_func) 65235783Skib return EINVAL; 66235783Skib 67235783Skib irq->irq = dev->irq; 68235783Skib 69235783Skib DRM_DEBUG("%d:%d:%d => IRQ %d\n", 70235783Skib irq->busnum, irq->devnum, irq->funcnum, irq->irq); 71235783Skib 72235783Skib return 0; 73235783Skib} 74235783Skib 75235783Skibstatic void 76235783Skibdrm_irq_handler_wrap(void *arg) 77235783Skib{ 78235783Skib struct drm_device *dev = arg; 79235783Skib 80235783Skib mtx_lock(&dev->irq_lock); 81235783Skib dev->driver->irq_handler(arg); 82235783Skib mtx_unlock(&dev->irq_lock); 83235783Skib} 84235783Skib 85235783Skibint 86235783Skibdrm_irq_install(struct drm_device *dev) 87235783Skib{ 88235783Skib int retcode; 89235783Skib 90235783Skib if (dev->irq == 0 || dev->dev_private == NULL) 91235783Skib return (EINVAL); 92235783Skib 93235783Skib DRM_DEBUG("irq=%d\n", dev->irq); 94235783Skib 95235783Skib DRM_LOCK(dev); 96235783Skib if (dev->irq_enabled) { 97235783Skib DRM_UNLOCK(dev); 98235783Skib return EBUSY; 99235783Skib } 100235783Skib dev->irq_enabled = 1; 101235783Skib 102235783Skib dev->context_flag = 0; 103235783Skib 104235783Skib /* Before installing handler */ 105235783Skib if (dev->driver->irq_preinstall) 106235783Skib dev->driver->irq_preinstall(dev); 107235783Skib DRM_UNLOCK(dev); 108235783Skib 109235783Skib /* Install handler */ 110235783Skib retcode = bus_setup_intr(dev->device, dev->irqr, 111235783Skib INTR_TYPE_TTY | INTR_MPSAFE, NULL, 112235783Skib (dev->driver->driver_features & DRIVER_LOCKLESS_IRQ) != 0 ? 113235783Skib drm_irq_handler_wrap : dev->driver->irq_handler, 114235783Skib dev, &dev->irqh); 115235783Skib if (retcode != 0) 116235783Skib goto err; 117235783Skib 118235783Skib /* After installing handler */ 119235783Skib DRM_LOCK(dev); 120235783Skib if (dev->driver->irq_postinstall) 121235783Skib dev->driver->irq_postinstall(dev); 122235783Skib DRM_UNLOCK(dev); 123235783Skib 124235783Skib return (0); 125235783Skiberr: 126235783Skib device_printf(dev->device, "Error setting interrupt: %d\n", retcode); 127235783Skib dev->irq_enabled = 0; 128235783Skib 129235783Skib return (retcode); 130235783Skib} 131235783Skib 132235783Skibint drm_irq_uninstall(struct drm_device *dev) 133235783Skib{ 134235783Skib int i; 135235783Skib 136235783Skib if (!dev->irq_enabled) 137235783Skib return EINVAL; 138235783Skib 139235783Skib dev->irq_enabled = 0; 140235783Skib 141235783Skib /* 142235783Skib * Wake up any waiters so they don't hang. 143235783Skib */ 144235783Skib if (dev->num_crtcs) { 145235783Skib mtx_lock(&dev->vbl_lock); 146235783Skib for (i = 0; i < dev->num_crtcs; i++) { 147235783Skib wakeup(&dev->_vblank_count[i]); 148235783Skib dev->vblank_enabled[i] = 0; 149235783Skib dev->last_vblank[i] = 150235783Skib dev->driver->get_vblank_counter(dev, i); 151235783Skib } 152235783Skib mtx_unlock(&dev->vbl_lock); 153235783Skib } 154235783Skib 155235783Skib DRM_DEBUG("irq=%d\n", dev->irq); 156235783Skib 157235783Skib if (dev->driver->irq_uninstall) 158235783Skib dev->driver->irq_uninstall(dev); 159235783Skib 160235783Skib DRM_UNLOCK(dev); 161235783Skib bus_teardown_intr(dev->device, dev->irqr, dev->irqh); 162235783Skib DRM_LOCK(dev); 163235783Skib 164235783Skib return 0; 165235783Skib} 166235783Skib 167235783Skibint drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) 168235783Skib{ 169235783Skib struct drm_control *ctl = data; 170235783Skib int err; 171235783Skib 172235783Skib switch (ctl->func) { 173235783Skib case DRM_INST_HANDLER: 174235783Skib /* Handle drivers whose DRM used to require IRQ setup but the 175235783Skib * no longer does. 176235783Skib */ 177235783Skib if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 178235783Skib return 0; 179235783Skib if (drm_core_check_feature(dev, DRIVER_MODESET)) 180235783Skib return 0; 181235783Skib if (dev->if_version < DRM_IF_VERSION(1, 2) && 182235783Skib ctl->irq != dev->irq) 183235783Skib return EINVAL; 184235783Skib return drm_irq_install(dev); 185235783Skib case DRM_UNINST_HANDLER: 186235783Skib if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 187235783Skib return 0; 188235783Skib if (drm_core_check_feature(dev, DRIVER_MODESET)) 189235783Skib return 0; 190235783Skib DRM_LOCK(dev); 191235783Skib err = drm_irq_uninstall(dev); 192235783Skib DRM_UNLOCK(dev); 193235783Skib return err; 194235783Skib default: 195235783Skib return EINVAL; 196235783Skib } 197235783Skib} 198235783Skib 199235783Skib#define NSEC_PER_USEC 1000L 200235783Skib#define NSEC_PER_SEC 1000000000L 201235783Skib 202235783Skibint64_t 203235783Skibtimeval_to_ns(const struct timeval *tv) 204235783Skib{ 205235783Skib return ((int64_t)tv->tv_sec * NSEC_PER_SEC) + 206235783Skib tv->tv_usec * NSEC_PER_USEC; 207235783Skib} 208235783Skib 209235783Skibstruct timeval 210235783Skibns_to_timeval(const int64_t nsec) 211235783Skib{ 212235783Skib struct timeval tv; 213263119Sdumbbell long rem; 214235783Skib 215235783Skib if (nsec == 0) { 216235783Skib tv.tv_sec = 0; 217235783Skib tv.tv_usec = 0; 218235783Skib return (tv); 219235783Skib } 220235783Skib 221235783Skib tv.tv_sec = nsec / NSEC_PER_SEC; 222235783Skib rem = nsec % NSEC_PER_SEC; 223235783Skib if (rem < 0) { 224235783Skib tv.tv_sec--; 225235783Skib rem += NSEC_PER_SEC; 226235783Skib } 227235783Skib tv.tv_usec = rem / 1000; 228235783Skib return (tv); 229235783Skib} 230235783Skib 231235783Skib/* 232235783Skib * Clear vblank timestamp buffer for a crtc. 233235783Skib */ 234235783Skibstatic void clear_vblank_timestamps(struct drm_device *dev, int crtc) 235235783Skib{ 236235783Skib memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0, 237235783Skib DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval)); 238235783Skib} 239235783Skib 240235783Skibstatic int64_t 241235783Skibabs64(int64_t x) 242235783Skib{ 243235783Skib 244235783Skib return (x < 0 ? -x : x); 245235783Skib} 246235783Skib 247235783Skib/* 248235783Skib * Disable vblank irq's on crtc, make sure that last vblank count 249235783Skib * of hardware and corresponding consistent software vblank counter 250235783Skib * are preserved, even if there are any spurious vblank irq's after 251235783Skib * disable. 252235783Skib */ 253235783Skibstatic void vblank_disable_and_save(struct drm_device *dev, int crtc) 254235783Skib{ 255235783Skib u32 vblcount; 256235783Skib int64_t diff_ns; 257235783Skib int vblrc; 258235783Skib struct timeval tvblank; 259235783Skib 260235783Skib /* Prevent vblank irq processing while disabling vblank irqs, 261235783Skib * so no updates of timestamps or count can happen after we've 262235783Skib * disabled. Needed to prevent races in case of delayed irq's. 263235783Skib */ 264235783Skib mtx_lock(&dev->vblank_time_lock); 265235783Skib 266235783Skib dev->driver->disable_vblank(dev, crtc); 267235783Skib dev->vblank_enabled[crtc] = 0; 268235783Skib 269235783Skib /* No further vblank irq's will be processed after 270235783Skib * this point. Get current hardware vblank count and 271235783Skib * vblank timestamp, repeat until they are consistent. 272235783Skib * 273235783Skib * FIXME: There is still a race condition here and in 274235783Skib * drm_update_vblank_count() which can cause off-by-one 275235783Skib * reinitialization of software vblank counter. If gpu 276235783Skib * vblank counter doesn't increment exactly at the leading 277235783Skib * edge of a vblank interval, then we can lose 1 count if 278235783Skib * we happen to execute between start of vblank and the 279235783Skib * delayed gpu counter increment. 280235783Skib */ 281235783Skib do { 282235783Skib dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); 283235783Skib vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); 284235783Skib } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc)); 285235783Skib 286235783Skib /* Compute time difference to stored timestamp of last vblank 287235783Skib * as updated by last invocation of drm_handle_vblank() in vblank irq. 288235783Skib */ 289235783Skib vblcount = atomic_read(&dev->_vblank_count[crtc]); 290235783Skib diff_ns = timeval_to_ns(&tvblank) - 291235783Skib timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); 292235783Skib 293235783Skib /* If there is at least 1 msec difference between the last stored 294235783Skib * timestamp and tvblank, then we are currently executing our 295235783Skib * disable inside a new vblank interval, the tvblank timestamp 296235783Skib * corresponds to this new vblank interval and the irq handler 297235783Skib * for this vblank didn't run yet and won't run due to our disable. 298235783Skib * Therefore we need to do the job of drm_handle_vblank() and 299235783Skib * increment the vblank counter by one to account for this vblank. 300235783Skib * 301235783Skib * Skip this step if there isn't any high precision timestamp 302235783Skib * available. In that case we can't account for this and just 303235783Skib * hope for the best. 304235783Skib */ 305235783Skib if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { 306235783Skib atomic_inc(&dev->_vblank_count[crtc]); 307235783Skib } 308235783Skib 309235783Skib /* Invalidate all timestamps while vblank irq's are off. */ 310235783Skib clear_vblank_timestamps(dev, crtc); 311235783Skib 312235783Skib mtx_unlock(&dev->vblank_time_lock); 313235783Skib} 314235783Skib 315235783Skibstatic void vblank_disable_fn(void * arg) 316235783Skib{ 317235783Skib struct drm_device *dev = (struct drm_device *)arg; 318235783Skib int i; 319235783Skib 320235783Skib if (!dev->vblank_disable_allowed) 321235783Skib return; 322235783Skib 323235783Skib for (i = 0; i < dev->num_crtcs; i++) { 324235783Skib mtx_lock(&dev->vbl_lock); 325235783Skib if (atomic_read(&dev->vblank_refcount[i]) == 0 && 326235783Skib dev->vblank_enabled[i]) { 327235783Skib DRM_DEBUG("disabling vblank on crtc %d\n", i); 328235783Skib vblank_disable_and_save(dev, i); 329235783Skib } 330235783Skib mtx_unlock(&dev->vbl_lock); 331235783Skib } 332235783Skib} 333235783Skib 334235783Skibvoid drm_vblank_cleanup(struct drm_device *dev) 335235783Skib{ 336235783Skib /* Bail if the driver didn't call drm_vblank_init() */ 337235783Skib if (dev->num_crtcs == 0) 338235783Skib return; 339235783Skib 340235783Skib callout_stop(&dev->vblank_disable_callout); 341235783Skib 342235783Skib vblank_disable_fn(dev); 343235783Skib 344235783Skib free(dev->_vblank_count, DRM_MEM_VBLANK); 345235783Skib free(dev->vblank_refcount, DRM_MEM_VBLANK); 346235783Skib free(dev->vblank_enabled, DRM_MEM_VBLANK); 347235783Skib free(dev->last_vblank, DRM_MEM_VBLANK); 348235783Skib free(dev->last_vblank_wait, DRM_MEM_VBLANK); 349235783Skib free(dev->vblank_inmodeset, DRM_MEM_VBLANK); 350235783Skib free(dev->_vblank_time, DRM_MEM_VBLANK); 351235783Skib 352235783Skib dev->num_crtcs = 0; 353235783Skib} 354235783Skib 355235783Skibint drm_vblank_init(struct drm_device *dev, int num_crtcs) 356235783Skib{ 357235783Skib int i; 358235783Skib 359235783Skib callout_init(&dev->vblank_disable_callout, CALLOUT_MPSAFE); 360235783Skib#if 0 361235783Skib mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); 362235783Skib#endif 363235783Skib mtx_init(&dev->vblank_time_lock, "drmvtl", NULL, MTX_DEF); 364235783Skib 365235783Skib dev->num_crtcs = num_crtcs; 366235783Skib 367235783Skib dev->_vblank_count = malloc(sizeof(atomic_t) * num_crtcs, 368235783Skib DRM_MEM_VBLANK, M_WAITOK); 369235783Skib dev->vblank_refcount = malloc(sizeof(atomic_t) * num_crtcs, 370235783Skib DRM_MEM_VBLANK, M_WAITOK); 371235783Skib dev->vblank_enabled = malloc(num_crtcs * sizeof(int), 372235783Skib DRM_MEM_VBLANK, M_WAITOK | M_ZERO); 373235783Skib dev->last_vblank = malloc(num_crtcs * sizeof(u32), 374235783Skib DRM_MEM_VBLANK, M_WAITOK | M_ZERO); 375235783Skib dev->last_vblank_wait = malloc(num_crtcs * sizeof(u32), 376235783Skib DRM_MEM_VBLANK, M_WAITOK | M_ZERO); 377235783Skib dev->vblank_inmodeset = malloc(num_crtcs * sizeof(int), 378235783Skib DRM_MEM_VBLANK, M_WAITOK | M_ZERO); 379235783Skib dev->_vblank_time = malloc(num_crtcs * DRM_VBLANKTIME_RBSIZE * 380235783Skib sizeof(struct timeval), DRM_MEM_VBLANK, M_WAITOK | M_ZERO); 381235783Skib DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n"); 382235783Skib 383235783Skib /* Driver specific high-precision vblank timestamping supported? */ 384235783Skib if (dev->driver->get_vblank_timestamp) 385235783Skib DRM_INFO("Driver supports precise vblank timestamp query.\n"); 386235783Skib else 387235783Skib DRM_INFO("No driver support for vblank timestamp query.\n"); 388235783Skib 389235783Skib /* Zero per-crtc vblank stuff */ 390235783Skib for (i = 0; i < num_crtcs; i++) { 391235783Skib atomic_set(&dev->_vblank_count[i], 0); 392235783Skib atomic_set(&dev->vblank_refcount[i], 0); 393235783Skib } 394235783Skib 395235783Skib dev->vblank_disable_allowed = 0; 396235783Skib return 0; 397235783Skib} 398235783Skib 399235783Skibvoid 400235783Skibdrm_calc_timestamping_constants(struct drm_crtc *crtc) 401235783Skib{ 402235783Skib int64_t linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; 403235783Skib uint64_t dotclock; 404235783Skib 405235783Skib /* Dot clock in Hz: */ 406235783Skib dotclock = (uint64_t) crtc->hwmode.clock * 1000; 407235783Skib 408235783Skib /* Fields of interlaced scanout modes are only halve a frame duration. 409235783Skib * Double the dotclock to get halve the frame-/line-/pixelduration. 410235783Skib */ 411235783Skib if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE) 412235783Skib dotclock *= 2; 413235783Skib 414235783Skib /* Valid dotclock? */ 415235783Skib if (dotclock > 0) { 416235783Skib /* Convert scanline length in pixels and video dot clock to 417235783Skib * line duration, frame duration and pixel duration in 418235783Skib * nanoseconds: 419235783Skib */ 420235783Skib pixeldur_ns = (int64_t)1000000000 / dotclock; 421235783Skib linedur_ns = ((uint64_t)crtc->hwmode.crtc_htotal * 422235783Skib 1000000000) / dotclock; 423235783Skib framedur_ns = (int64_t)crtc->hwmode.crtc_vtotal * linedur_ns; 424235783Skib } else 425235783Skib DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", 426235783Skib crtc->base.id); 427235783Skib 428235783Skib crtc->pixeldur_ns = pixeldur_ns; 429235783Skib crtc->linedur_ns = linedur_ns; 430235783Skib crtc->framedur_ns = framedur_ns; 431235783Skib 432235783Skib DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", 433235783Skib crtc->base.id, crtc->hwmode.crtc_htotal, 434235783Skib crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); 435235783Skib DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", 436235783Skib crtc->base.id, (int) dotclock/1000, (int) framedur_ns, 437235783Skib (int) linedur_ns, (int) pixeldur_ns); 438235783Skib} 439235783Skib 440235783Skib/** 441235783Skib * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms 442235783Skib * drivers. Implements calculation of exact vblank timestamps from 443235783Skib * given drm_display_mode timings and current video scanout position 444235783Skib * of a crtc. This can be called from within get_vblank_timestamp() 445235783Skib * implementation of a kms driver to implement the actual timestamping. 446235783Skib * 447235783Skib * Should return timestamps conforming to the OML_sync_control OpenML 448235783Skib * extension specification. The timestamp corresponds to the end of 449235783Skib * the vblank interval, aka start of scanout of topmost-leftmost display 450235783Skib * pixel in the following video frame. 451235783Skib * 452235783Skib * Requires support for optional dev->driver->get_scanout_position() 453235783Skib * in kms driver, plus a bit of setup code to provide a drm_display_mode 454235783Skib * that corresponds to the true scanout timing. 455235783Skib * 456235783Skib * The current implementation only handles standard video modes. It 457235783Skib * returns as no operation if a doublescan or interlaced video mode is 458235783Skib * active. Higher level code is expected to handle this. 459235783Skib * 460235783Skib * @dev: DRM device. 461235783Skib * @crtc: Which crtc's vblank timestamp to retrieve. 462235783Skib * @max_error: Desired maximum allowable error in timestamps (nanosecs). 463235783Skib * On return contains true maximum error of timestamp. 464235783Skib * @vblank_time: Pointer to struct timeval which should receive the timestamp. 465235783Skib * @flags: Flags to pass to driver: 466235783Skib * 0 = Default. 467235783Skib * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. 468235783Skib * @refcrtc: drm_crtc* of crtc which defines scanout timing. 469235783Skib * 470235783Skib * Returns negative value on error, failure or if not supported in current 471235783Skib * video mode: 472235783Skib * 473235783Skib * -EINVAL - Invalid crtc. 474235783Skib * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. 475235783Skib * -ENOTSUPP - Function not supported in current display mode. 476235783Skib * -EIO - Failed, e.g., due to failed scanout position query. 477235783Skib * 478235783Skib * Returns or'ed positive status flags on success: 479235783Skib * 480235783Skib * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. 481235783Skib * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. 482235783Skib * 483235783Skib */ 484235783Skibint 485235783Skibdrm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, 486235783Skib int *max_error, struct timeval *vblank_time, unsigned flags, 487235783Skib struct drm_crtc *refcrtc) 488235783Skib{ 489235783Skib struct timeval stime, raw_time; 490235783Skib struct drm_display_mode *mode; 491235783Skib int vbl_status, vtotal, vdisplay; 492235783Skib int vpos, hpos, i; 493235783Skib int64_t framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; 494235783Skib bool invbl; 495235783Skib 496235783Skib if (crtc < 0 || crtc >= dev->num_crtcs) { 497235783Skib DRM_ERROR("Invalid crtc %d\n", crtc); 498235783Skib return -EINVAL; 499235783Skib } 500235783Skib 501235783Skib /* Scanout position query not supported? Should not happen. */ 502235783Skib if (!dev->driver->get_scanout_position) { 503235783Skib DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); 504235783Skib return -EIO; 505235783Skib } 506235783Skib 507235783Skib mode = &refcrtc->hwmode; 508235783Skib vtotal = mode->crtc_vtotal; 509235783Skib vdisplay = mode->crtc_vdisplay; 510235783Skib 511235783Skib /* Durations of frames, lines, pixels in nanoseconds. */ 512235783Skib framedur_ns = refcrtc->framedur_ns; 513235783Skib linedur_ns = refcrtc->linedur_ns; 514235783Skib pixeldur_ns = refcrtc->pixeldur_ns; 515235783Skib 516235783Skib /* If mode timing undefined, just return as no-op: 517235783Skib * Happens during initial modesetting of a crtc. 518235783Skib */ 519235783Skib if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { 520235783Skib DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); 521235783Skib return -EAGAIN; 522235783Skib } 523235783Skib 524235783Skib /* Get current scanout position with system timestamp. 525235783Skib * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times 526235783Skib * if single query takes longer than max_error nanoseconds. 527235783Skib * 528235783Skib * This guarantees a tight bound on maximum error if 529235783Skib * code gets preempted or delayed for some reason. 530235783Skib */ 531235783Skib for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { 532235783Skib /* Disable preemption to make it very likely to 533235783Skib * succeed in the first iteration. 534235783Skib */ 535235783Skib critical_enter(); 536235783Skib 537235783Skib /* Get system timestamp before query. */ 538235783Skib getmicrouptime(&stime); 539235783Skib 540235783Skib /* Get vertical and horizontal scanout pos. vpos, hpos. */ 541235783Skib vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos); 542235783Skib 543235783Skib /* Get system timestamp after query. */ 544235783Skib getmicrouptime(&raw_time); 545235783Skib 546235783Skib critical_exit(); 547235783Skib 548235783Skib /* Return as no-op if scanout query unsupported or failed. */ 549235783Skib if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { 550235783Skib DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", 551235783Skib crtc, vbl_status); 552235783Skib return -EIO; 553235783Skib } 554235783Skib 555235783Skib duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime); 556235783Skib 557235783Skib /* Accept result with < max_error nsecs timing uncertainty. */ 558235783Skib if (duration_ns <= (int64_t) *max_error) 559235783Skib break; 560235783Skib } 561235783Skib 562235783Skib /* Noisy system timing? */ 563235783Skib if (i == DRM_TIMESTAMP_MAXRETRIES) { 564235783Skib DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", 565235783Skib crtc, (int) duration_ns/1000, *max_error/1000, i); 566235783Skib } 567235783Skib 568235783Skib /* Return upper bound of timestamp precision error. */ 569235783Skib *max_error = (int) duration_ns; 570235783Skib 571235783Skib /* Check if in vblank area: 572235783Skib * vpos is >=0 in video scanout area, but negative 573235783Skib * within vblank area, counting down the number of lines until 574235783Skib * start of scanout. 575235783Skib */ 576235783Skib invbl = vbl_status & DRM_SCANOUTPOS_INVBL; 577235783Skib 578235783Skib /* Convert scanout position into elapsed time at raw_time query 579235783Skib * since start of scanout at first display scanline. delta_ns 580235783Skib * can be negative if start of scanout hasn't happened yet. 581235783Skib */ 582235783Skib delta_ns = (int64_t)vpos * linedur_ns + (int64_t)hpos * pixeldur_ns; 583235783Skib 584235783Skib /* Is vpos outside nominal vblank area, but less than 585235783Skib * 1/100 of a frame height away from start of vblank? 586235783Skib * If so, assume this isn't a massively delayed vblank 587235783Skib * interrupt, but a vblank interrupt that fired a few 588235783Skib * microseconds before true start of vblank. Compensate 589235783Skib * by adding a full frame duration to the final timestamp. 590235783Skib * Happens, e.g., on ATI R500, R600. 591235783Skib * 592235783Skib * We only do this if DRM_CALLED_FROM_VBLIRQ. 593235783Skib */ 594235783Skib if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && 595235783Skib ((vdisplay - vpos) < vtotal / 100)) { 596235783Skib delta_ns = delta_ns - framedur_ns; 597235783Skib 598235783Skib /* Signal this correction as "applied". */ 599235783Skib vbl_status |= 0x8; 600235783Skib } 601235783Skib 602235783Skib /* Subtract time delta from raw timestamp to get final 603235783Skib * vblank_time timestamp for end of vblank. 604235783Skib */ 605235783Skib *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns); 606235783Skib 607235783Skib DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %jd.%jd -> %jd.%jd [e %d us, %d rep]\n", 608235783Skib crtc, (int)vbl_status, hpos, vpos, (uintmax_t)raw_time.tv_sec, 609235783Skib (uintmax_t)raw_time.tv_usec, (uintmax_t)vblank_time->tv_sec, 610235783Skib (uintmax_t)vblank_time->tv_usec, (int)duration_ns/1000, i); 611235783Skib 612235783Skib vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; 613235783Skib if (invbl) 614235783Skib vbl_status |= DRM_VBLANKTIME_INVBL; 615235783Skib 616235783Skib return vbl_status; 617235783Skib} 618235783Skib 619235783Skib/** 620235783Skib * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent 621235783Skib * vblank interval. 622235783Skib * 623235783Skib * @dev: DRM device 624235783Skib * @crtc: which crtc's vblank timestamp to retrieve 625235783Skib * @tvblank: Pointer to target struct timeval which should receive the timestamp 626235783Skib * @flags: Flags to pass to driver: 627235783Skib * 0 = Default. 628235783Skib * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. 629235783Skib * 630235783Skib * Fetches the system timestamp corresponding to the time of the most recent 631235783Skib * vblank interval on specified crtc. May call into kms-driver to 632235783Skib * compute the timestamp with a high-precision GPU specific method. 633235783Skib * 634235783Skib * Returns zero if timestamp originates from uncorrected do_gettimeofday() 635235783Skib * call, i.e., it isn't very precisely locked to the true vblank. 636235783Skib * 637235783Skib * Returns non-zero if timestamp is considered to be very precise. 638235783Skib */ 639235783Skibu32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, 640235783Skib struct timeval *tvblank, unsigned flags) 641235783Skib{ 642235783Skib int ret = 0; 643235783Skib 644235783Skib /* Define requested maximum error on timestamps (nanoseconds). */ 645235783Skib int max_error = (int) drm_timestamp_precision * 1000; 646235783Skib 647235783Skib /* Query driver if possible and precision timestamping enabled. */ 648235783Skib if (dev->driver->get_vblank_timestamp && (max_error > 0)) { 649235783Skib ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, 650235783Skib tvblank, flags); 651235783Skib if (ret > 0) 652235783Skib return (u32) ret; 653235783Skib } 654235783Skib 655235783Skib /* GPU high precision timestamp query unsupported or failed. 656235783Skib * Return gettimeofday timestamp as best estimate. 657235783Skib */ 658235783Skib microtime(tvblank); 659235783Skib 660235783Skib return 0; 661235783Skib} 662235783Skib 663235783Skib/** 664235783Skib * drm_vblank_count - retrieve "cooked" vblank counter value 665235783Skib * @dev: DRM device 666235783Skib * @crtc: which counter to retrieve 667235783Skib * 668235783Skib * Fetches the "cooked" vblank count value that represents the number of 669235783Skib * vblank events since the system was booted, including lost events due to 670235783Skib * modesetting activity. 671235783Skib */ 672235783Skibu32 drm_vblank_count(struct drm_device *dev, int crtc) 673235783Skib{ 674235783Skib return atomic_read(&dev->_vblank_count[crtc]); 675235783Skib} 676235783Skib 677235783Skib/** 678235783Skib * drm_vblank_count_and_time - retrieve "cooked" vblank counter value 679235783Skib * and the system timestamp corresponding to that vblank counter value. 680235783Skib * 681235783Skib * @dev: DRM device 682235783Skib * @crtc: which counter to retrieve 683235783Skib * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. 684235783Skib * 685235783Skib * Fetches the "cooked" vblank count value that represents the number of 686235783Skib * vblank events since the system was booted, including lost events due to 687235783Skib * modesetting activity. Returns corresponding system timestamp of the time 688235783Skib * of the vblank interval that corresponds to the current value vblank counter 689235783Skib * value. 690235783Skib */ 691235783Skibu32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, 692235783Skib struct timeval *vblanktime) 693235783Skib{ 694235783Skib u32 cur_vblank; 695235783Skib 696235783Skib /* Read timestamp from slot of _vblank_time ringbuffer 697235783Skib * that corresponds to current vblank count. Retry if 698235783Skib * count has incremented during readout. This works like 699235783Skib * a seqlock. 700235783Skib */ 701235783Skib do { 702235783Skib cur_vblank = atomic_read(&dev->_vblank_count[crtc]); 703235783Skib *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); 704235783Skib rmb(); 705235783Skib } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); 706235783Skib 707235783Skib return cur_vblank; 708235783Skib} 709235783Skib 710235783Skib/** 711235783Skib * drm_update_vblank_count - update the master vblank counter 712235783Skib * @dev: DRM device 713235783Skib * @crtc: counter to update 714235783Skib * 715235783Skib * Call back into the driver to update the appropriate vblank counter 716235783Skib * (specified by @crtc). Deal with wraparound, if it occurred, and 717235783Skib * update the last read value so we can deal with wraparound on the next 718235783Skib * call if necessary. 719235783Skib * 720235783Skib * Only necessary when going from off->on, to account for frames we 721235783Skib * didn't get an interrupt for. 722235783Skib * 723235783Skib * Note: caller must hold dev->vbl_lock since this reads & writes 724235783Skib * device vblank fields. 725235783Skib */ 726235783Skibstatic void drm_update_vblank_count(struct drm_device *dev, int crtc) 727235783Skib{ 728235783Skib u32 cur_vblank, diff, tslot, rc; 729235783Skib struct timeval t_vblank; 730235783Skib 731235783Skib /* 732235783Skib * Interrupts were disabled prior to this call, so deal with counter 733235783Skib * wrap if needed. 734235783Skib * NOTE! It's possible we lost a full dev->max_vblank_count events 735235783Skib * here if the register is small or we had vblank interrupts off for 736235783Skib * a long time. 737235783Skib * 738235783Skib * We repeat the hardware vblank counter & timestamp query until 739235783Skib * we get consistent results. This to prevent races between gpu 740235783Skib * updating its hardware counter while we are retrieving the 741235783Skib * corresponding vblank timestamp. 742235783Skib */ 743235783Skib do { 744235783Skib cur_vblank = dev->driver->get_vblank_counter(dev, crtc); 745235783Skib rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); 746235783Skib } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); 747235783Skib 748235783Skib /* Deal with counter wrap */ 749235783Skib diff = cur_vblank - dev->last_vblank[crtc]; 750235783Skib if (cur_vblank < dev->last_vblank[crtc]) { 751235783Skib diff += dev->max_vblank_count; 752235783Skib 753235783Skib DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", 754235783Skib crtc, dev->last_vblank[crtc], cur_vblank, diff); 755235783Skib } 756235783Skib 757235783Skib DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", 758235783Skib crtc, diff); 759235783Skib 760235783Skib /* Reinitialize corresponding vblank timestamp if high-precision query 761235783Skib * available. Skip this step if query unsupported or failed. Will 762235783Skib * reinitialize delayed at next vblank interrupt in that case. 763235783Skib */ 764235783Skib if (rc) { 765235783Skib tslot = atomic_read(&dev->_vblank_count[crtc]) + diff; 766235783Skib vblanktimestamp(dev, crtc, tslot) = t_vblank; 767235783Skib } 768235783Skib 769235783Skib atomic_add(diff, &dev->_vblank_count[crtc]); 770235783Skib} 771235783Skib 772235783Skib/** 773235783Skib * drm_vblank_get - get a reference count on vblank events 774235783Skib * @dev: DRM device 775235783Skib * @crtc: which CRTC to own 776235783Skib * 777235783Skib * Acquire a reference count on vblank events to avoid having them disabled 778235783Skib * while in use. 779235783Skib * 780235783Skib * RETURNS 781235783Skib * Zero on success, nonzero on failure. 782235783Skib */ 783235783Skibint drm_vblank_get(struct drm_device *dev, int crtc) 784235783Skib{ 785235783Skib int ret = 0; 786235783Skib 787235783Skib mtx_lock(&dev->vbl_lock); 788235783Skib /* Going from 0->1 means we have to enable interrupts again */ 789262988Sdumbbell if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { 790235783Skib mtx_lock(&dev->vblank_time_lock); 791235783Skib if (!dev->vblank_enabled[crtc]) { 792235783Skib /* Enable vblank irqs under vblank_time_lock protection. 793235783Skib * All vblank count & timestamp updates are held off 794235783Skib * until we are done reinitializing master counter and 795235783Skib * timestamps. Filtercode in drm_handle_vblank() will 796235783Skib * prevent double-accounting of same vblank interval. 797235783Skib */ 798235783Skib ret = -dev->driver->enable_vblank(dev, crtc); 799235783Skib DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", 800235783Skib crtc, ret); 801235783Skib if (ret) 802235783Skib atomic_dec(&dev->vblank_refcount[crtc]); 803235783Skib else { 804235783Skib dev->vblank_enabled[crtc] = 1; 805235783Skib drm_update_vblank_count(dev, crtc); 806235783Skib } 807235783Skib } 808235783Skib mtx_unlock(&dev->vblank_time_lock); 809235783Skib } else { 810235783Skib if (!dev->vblank_enabled[crtc]) { 811235783Skib atomic_dec(&dev->vblank_refcount[crtc]); 812235783Skib ret = EINVAL; 813235783Skib } 814235783Skib } 815235783Skib mtx_unlock(&dev->vbl_lock); 816235783Skib 817235783Skib return ret; 818235783Skib} 819235783Skib 820235783Skib/** 821235783Skib * drm_vblank_put - give up ownership of vblank events 822235783Skib * @dev: DRM device 823235783Skib * @crtc: which counter to give up 824235783Skib * 825235783Skib * Release ownership of a given vblank counter, turning off interrupts 826235783Skib * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. 827235783Skib */ 828235783Skibvoid drm_vblank_put(struct drm_device *dev, int crtc) 829235783Skib{ 830235783Skib KASSERT(atomic_read(&dev->vblank_refcount[crtc]) != 0, 831235783Skib ("Too many drm_vblank_put for crtc %d", crtc)); 832235783Skib 833235783Skib /* Last user schedules interrupt disable */ 834262988Sdumbbell if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) && 835235783Skib (drm_vblank_offdelay > 0)) 836235783Skib callout_reset(&dev->vblank_disable_callout, 837235783Skib (drm_vblank_offdelay * DRM_HZ) / 1000, 838235783Skib vblank_disable_fn, dev); 839235783Skib} 840235783Skib 841235783Skibvoid drm_vblank_off(struct drm_device *dev, int crtc) 842235783Skib{ 843235783Skib struct drm_pending_vblank_event *e, *t; 844235783Skib struct timeval now; 845235783Skib unsigned int seq; 846235783Skib 847235783Skib mtx_lock(&dev->vbl_lock); 848235783Skib vblank_disable_and_save(dev, crtc); 849235783Skib mtx_lock(&dev->event_lock); 850235783Skib wakeup(&dev->_vblank_count[crtc]); 851235783Skib 852235783Skib /* Send any queued vblank events, lest the natives grow disquiet */ 853235783Skib seq = drm_vblank_count_and_time(dev, crtc, &now); 854235783Skib list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 855235783Skib if (e->pipe != crtc) 856235783Skib continue; 857235783Skib DRM_DEBUG("Sending premature vblank event on disable: \ 858235783Skib wanted %d, current %d\n", 859235783Skib e->event.sequence, seq); 860235783Skib 861235783Skib e->event.sequence = seq; 862235783Skib e->event.tv_sec = now.tv_sec; 863235783Skib e->event.tv_usec = now.tv_usec; 864235783Skib drm_vblank_put(dev, e->pipe); 865235783Skib list_move_tail(&e->base.link, &e->base.file_priv->event_list); 866235783Skib drm_event_wakeup(&e->base); 867235783Skib CTR3(KTR_DRM, "vblank_event_delivered %d %d %d", 868235783Skib e->base.pid, e->pipe, e->event.sequence); 869235783Skib } 870235783Skib 871235783Skib mtx_unlock(&dev->event_lock); 872235783Skib mtx_unlock(&dev->vbl_lock); 873235783Skib} 874235783Skib 875235783Skib/** 876235783Skib * drm_vblank_pre_modeset - account for vblanks across mode sets 877235783Skib * @dev: DRM device 878235783Skib * @crtc: CRTC in question 879235783Skib * @post: post or pre mode set? 880235783Skib * 881235783Skib * Account for vblank events across mode setting events, which will likely 882235783Skib * reset the hardware frame counter. 883235783Skib */ 884235783Skibvoid drm_vblank_pre_modeset(struct drm_device *dev, int crtc) 885235783Skib{ 886235783Skib /* vblank is not initialized (IRQ not installed ?) */ 887235783Skib if (!dev->num_crtcs) 888235783Skib return; 889235783Skib /* 890235783Skib * To avoid all the problems that might happen if interrupts 891235783Skib * were enabled/disabled around or between these calls, we just 892235783Skib * have the kernel take a reference on the CRTC (just once though 893235783Skib * to avoid corrupting the count if multiple, mismatch calls occur), 894235783Skib * so that interrupts remain enabled in the interim. 895235783Skib */ 896235783Skib if (!dev->vblank_inmodeset[crtc]) { 897235783Skib dev->vblank_inmodeset[crtc] = 0x1; 898235783Skib if (drm_vblank_get(dev, crtc) == 0) 899235783Skib dev->vblank_inmodeset[crtc] |= 0x2; 900235783Skib } 901235783Skib} 902235783Skib 903235783Skibvoid drm_vblank_post_modeset(struct drm_device *dev, int crtc) 904235783Skib{ 905235783Skib 906235783Skib if (dev->vblank_inmodeset[crtc]) { 907235783Skib mtx_lock(&dev->vbl_lock); 908235783Skib dev->vblank_disable_allowed = 1; 909235783Skib mtx_unlock(&dev->vbl_lock); 910235783Skib 911235783Skib if (dev->vblank_inmodeset[crtc] & 0x2) 912235783Skib drm_vblank_put(dev, crtc); 913235783Skib 914235783Skib dev->vblank_inmodeset[crtc] = 0; 915235783Skib } 916235783Skib} 917235783Skib 918235783Skib/** 919235783Skib * drm_modeset_ctl - handle vblank event counter changes across mode switch 920235783Skib * @DRM_IOCTL_ARGS: standard ioctl arguments 921235783Skib * 922235783Skib * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET 923235783Skib * ioctls around modesetting so that any lost vblank events are accounted for. 924235783Skib * 925235783Skib * Generally the counter will reset across mode sets. If interrupts are 926235783Skib * enabled around this call, we don't have to do anything since the counter 927235783Skib * will have already been incremented. 928235783Skib */ 929235783Skibint drm_modeset_ctl(struct drm_device *dev, void *data, 930235783Skib struct drm_file *file_priv) 931235783Skib{ 932235783Skib struct drm_modeset_ctl *modeset = data; 933235783Skib int ret = 0; 934235783Skib unsigned int crtc; 935235783Skib 936235783Skib /* If drm_vblank_init() hasn't been called yet, just no-op */ 937235783Skib if (!dev->num_crtcs) 938235783Skib goto out; 939235783Skib 940235783Skib crtc = modeset->crtc; 941235783Skib if (crtc >= dev->num_crtcs) { 942235783Skib ret = -EINVAL; 943235783Skib goto out; 944235783Skib } 945235783Skib 946235783Skib switch (modeset->cmd) { 947235783Skib case _DRM_PRE_MODESET: 948235783Skib drm_vblank_pre_modeset(dev, crtc); 949235783Skib break; 950235783Skib case _DRM_POST_MODESET: 951235783Skib drm_vblank_post_modeset(dev, crtc); 952235783Skib break; 953235783Skib default: 954235783Skib ret = -EINVAL; 955235783Skib break; 956235783Skib } 957235783Skib 958235783Skibout: 959235783Skib return ret; 960235783Skib} 961235783Skib 962235783Skibstatic void 963235783Skibdrm_vblank_event_destroy(struct drm_pending_event *e) 964235783Skib{ 965235783Skib 966235783Skib free(e, DRM_MEM_VBLANK); 967235783Skib} 968235783Skib 969235783Skibstatic int drm_queue_vblank_event(struct drm_device *dev, int pipe, 970235783Skib union drm_wait_vblank *vblwait, 971235783Skib struct drm_file *file_priv) 972235783Skib{ 973235783Skib struct drm_pending_vblank_event *e; 974235783Skib struct timeval now; 975235783Skib unsigned int seq; 976235783Skib int ret; 977235783Skib 978235783Skib e = malloc(sizeof *e, DRM_MEM_VBLANK, M_WAITOK | M_ZERO); 979235783Skib 980235783Skib e->pipe = pipe; 981235783Skib e->base.pid = curproc->p_pid; 982235783Skib e->event.base.type = DRM_EVENT_VBLANK; 983235783Skib e->event.base.length = sizeof e->event; 984235783Skib e->event.user_data = vblwait->request.signal; 985235783Skib e->base.event = &e->event.base; 986235783Skib e->base.file_priv = file_priv; 987235783Skib e->base.destroy = drm_vblank_event_destroy; 988235783Skib 989235783Skib mtx_lock(&dev->event_lock); 990235783Skib 991235783Skib if (file_priv->event_space < sizeof e->event) { 992235783Skib ret = EBUSY; 993235783Skib goto err_unlock; 994235783Skib } 995235783Skib 996235783Skib file_priv->event_space -= sizeof e->event; 997235783Skib seq = drm_vblank_count_and_time(dev, pipe, &now); 998235783Skib 999235783Skib if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && 1000235783Skib (seq - vblwait->request.sequence) <= (1 << 23)) { 1001235783Skib vblwait->request.sequence = seq + 1; 1002235783Skib vblwait->reply.sequence = vblwait->request.sequence; 1003235783Skib } 1004235783Skib 1005235783Skib DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n", 1006235783Skib vblwait->request.sequence, seq, pipe); 1007235783Skib 1008235783Skib CTR4(KTR_DRM, "vblank_event_queued %d %d rt %x %d", curproc->p_pid, pipe, 1009235783Skib vblwait->request.type, vblwait->request.sequence); 1010235783Skib 1011235783Skib e->event.sequence = vblwait->request.sequence; 1012235783Skib if ((seq - vblwait->request.sequence) <= (1 << 23)) { 1013235783Skib e->event.sequence = seq; 1014235783Skib e->event.tv_sec = now.tv_sec; 1015235783Skib e->event.tv_usec = now.tv_usec; 1016235783Skib drm_vblank_put(dev, pipe); 1017235783Skib list_add_tail(&e->base.link, &e->base.file_priv->event_list); 1018235783Skib drm_event_wakeup(&e->base); 1019235783Skib vblwait->reply.sequence = seq; 1020235783Skib CTR3(KTR_DRM, "vblank_event_wakeup p1 %d %d %d", curproc->p_pid, 1021235783Skib pipe, vblwait->request.sequence); 1022235783Skib } else { 1023235783Skib /* drm_handle_vblank_events will call drm_vblank_put */ 1024235783Skib list_add_tail(&e->base.link, &dev->vblank_event_list); 1025235783Skib vblwait->reply.sequence = vblwait->request.sequence; 1026235783Skib } 1027235783Skib 1028235783Skib mtx_unlock(&dev->event_lock); 1029235783Skib 1030235783Skib return 0; 1031235783Skib 1032235783Skiberr_unlock: 1033235783Skib mtx_unlock(&dev->event_lock); 1034235783Skib free(e, DRM_MEM_VBLANK); 1035235783Skib drm_vblank_put(dev, pipe); 1036235783Skib return ret; 1037235783Skib} 1038235783Skib 1039235783Skib/** 1040235783Skib * Wait for VBLANK. 1041235783Skib * 1042235783Skib * \param inode device inode. 1043235783Skib * \param file_priv DRM file private. 1044235783Skib * \param cmd command. 1045235783Skib * \param data user argument, pointing to a drm_wait_vblank structure. 1046235783Skib * \return zero on success or a negative number on failure. 1047235783Skib * 1048235783Skib * This function enables the vblank interrupt on the pipe requested, then 1049235783Skib * sleeps waiting for the requested sequence number to occur, and drops 1050235783Skib * the vblank interrupt refcount afterwards. (vblank irq disable follows that 1051235783Skib * after a timeout with no further vblank waits scheduled). 1052235783Skib */ 1053235783Skibint drm_wait_vblank(struct drm_device *dev, void *data, 1054235783Skib struct drm_file *file_priv) 1055235783Skib{ 1056235783Skib union drm_wait_vblank *vblwait = data; 1057235783Skib int ret = 0; 1058235783Skib unsigned int flags, seq, crtc, high_crtc; 1059235783Skib 1060235783Skib if (/*(!drm_dev_to_irq(dev)) || */(!dev->irq_enabled)) 1061235783Skib return (EINVAL); 1062235783Skib 1063235783Skib if (vblwait->request.type & _DRM_VBLANK_SIGNAL) 1064235783Skib return (EINVAL); 1065235783Skib 1066235783Skib if (vblwait->request.type & 1067235783Skib ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 1068235783Skib _DRM_VBLANK_HIGH_CRTC_MASK)) { 1069235783Skib DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", 1070235783Skib vblwait->request.type, 1071235783Skib (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | 1072235783Skib _DRM_VBLANK_HIGH_CRTC_MASK)); 1073235783Skib return (EINVAL); 1074235783Skib } 1075235783Skib 1076235783Skib flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; 1077235783Skib high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); 1078235783Skib if (high_crtc) 1079235783Skib crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT; 1080235783Skib else 1081235783Skib crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; 1082235783Skib if (crtc >= dev->num_crtcs) 1083235783Skib return (EINVAL); 1084235783Skib 1085235783Skib ret = drm_vblank_get(dev, crtc); 1086235783Skib if (ret) { 1087235783Skib DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); 1088235783Skib return (ret); 1089235783Skib } 1090235783Skib seq = drm_vblank_count(dev, crtc); 1091235783Skib 1092235783Skib switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { 1093235783Skib case _DRM_VBLANK_RELATIVE: 1094235783Skib vblwait->request.sequence += seq; 1095235783Skib vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; 1096235783Skib case _DRM_VBLANK_ABSOLUTE: 1097235783Skib break; 1098235783Skib default: 1099235783Skib ret = (EINVAL); 1100235783Skib goto done; 1101235783Skib } 1102235783Skib 1103235783Skib if (flags & _DRM_VBLANK_EVENT) { 1104235783Skib /* must hold on to the vblank ref until the event fires 1105235783Skib * drm_vblank_put will be called asynchronously 1106235783Skib */ 1107235783Skib return drm_queue_vblank_event(dev, crtc, vblwait, file_priv); 1108235783Skib } 1109235783Skib 1110235783Skib if ((flags & _DRM_VBLANK_NEXTONMISS) && 1111235783Skib (seq - vblwait->request.sequence) <= (1<<23)) { 1112235783Skib vblwait->request.sequence = seq + 1; 1113235783Skib } 1114235783Skib 1115235783Skib dev->last_vblank_wait[crtc] = vblwait->request.sequence; 1116235783Skib mtx_lock(&dev->vblank_time_lock); 1117235783Skib while (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) > 1118235783Skib (1 << 23)) && dev->irq_enabled) { 1119235783Skib /* 1120235783Skib * The wakeups from the drm_irq_uninstall() and 1121235783Skib * drm_vblank_off() may be lost there since vbl_lock 1122235783Skib * is not held. Then, the timeout will wake us; the 3 1123235783Skib * seconds delay should not be a problem for 1124235783Skib * application when crtc is disabled or irq 1125235783Skib * uninstalled anyway. 1126235783Skib */ 1127235783Skib ret = msleep(&dev->_vblank_count[crtc], &dev->vblank_time_lock, 1128235783Skib PCATCH, "drmvbl", 3 * hz); 1129235783Skib if (ret != 0) 1130235783Skib break; 1131235783Skib } 1132235783Skib mtx_unlock(&dev->vblank_time_lock); 1133235783Skib if (ret != EINTR) { 1134235783Skib struct timeval now; 1135235783Skib long reply_seq; 1136235783Skib 1137235783Skib reply_seq = drm_vblank_count_and_time(dev, crtc, &now); 1138235783Skib CTR5(KTR_DRM, "wait_vblank %d %d rt %x success %d %d", 1139235783Skib curproc->p_pid, crtc, vblwait->request.type, 1140235783Skib vblwait->request.sequence, reply_seq); 1141235783Skib vblwait->reply.sequence = reply_seq; 1142235783Skib vblwait->reply.tval_sec = now.tv_sec; 1143235783Skib vblwait->reply.tval_usec = now.tv_usec; 1144235783Skib } else { 1145235783Skib CTR5(KTR_DRM, "wait_vblank %d %d rt %x error %d %d", 1146235783Skib curproc->p_pid, crtc, vblwait->request.type, ret, 1147235783Skib vblwait->request.sequence); 1148235783Skib } 1149235783Skib 1150235783Skibdone: 1151235783Skib drm_vblank_put(dev, crtc); 1152235783Skib return ret; 1153235783Skib} 1154235783Skib 1155235783Skibvoid drm_handle_vblank_events(struct drm_device *dev, int crtc) 1156235783Skib{ 1157235783Skib struct drm_pending_vblank_event *e, *t; 1158235783Skib struct timeval now; 1159235783Skib unsigned int seq; 1160235783Skib 1161235783Skib seq = drm_vblank_count_and_time(dev, crtc, &now); 1162235783Skib CTR2(KTR_DRM, "drm_handle_vblank_events %d %d", seq, crtc); 1163235783Skib 1164235783Skib mtx_lock(&dev->event_lock); 1165235783Skib 1166235783Skib list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { 1167235783Skib if (e->pipe != crtc) 1168235783Skib continue; 1169235783Skib if ((seq - e->event.sequence) > (1<<23)) 1170235783Skib continue; 1171235783Skib 1172235783Skib e->event.sequence = seq; 1173235783Skib e->event.tv_sec = now.tv_sec; 1174235783Skib e->event.tv_usec = now.tv_usec; 1175235783Skib drm_vblank_put(dev, e->pipe); 1176235783Skib list_move_tail(&e->base.link, &e->base.file_priv->event_list); 1177235783Skib drm_event_wakeup(&e->base); 1178235783Skib CTR3(KTR_DRM, "vblank_event_wakeup p2 %d %d %d", e->base.pid, 1179235783Skib e->pipe, e->event.sequence); 1180235783Skib } 1181235783Skib 1182235783Skib mtx_unlock(&dev->event_lock); 1183235783Skib} 1184235783Skib 1185235783Skib/** 1186235783Skib * drm_handle_vblank - handle a vblank event 1187235783Skib * @dev: DRM device 1188235783Skib * @crtc: where this event occurred 1189235783Skib * 1190235783Skib * Drivers should call this routine in their vblank interrupt handlers to 1191235783Skib * update the vblank counter and send any signals that may be pending. 1192235783Skib */ 1193235783Skibbool drm_handle_vblank(struct drm_device *dev, int crtc) 1194235783Skib{ 1195235783Skib u32 vblcount; 1196235783Skib int64_t diff_ns; 1197235783Skib struct timeval tvblank; 1198235783Skib 1199235783Skib if (!dev->num_crtcs) 1200235783Skib return false; 1201235783Skib 1202235783Skib /* Need timestamp lock to prevent concurrent execution with 1203235783Skib * vblank enable/disable, as this would cause inconsistent 1204235783Skib * or corrupted timestamps and vblank counts. 1205235783Skib */ 1206235783Skib mtx_lock(&dev->vblank_time_lock); 1207235783Skib 1208235783Skib /* Vblank irq handling disabled. Nothing to do. */ 1209235783Skib if (!dev->vblank_enabled[crtc]) { 1210235783Skib mtx_unlock(&dev->vblank_time_lock); 1211235783Skib return false; 1212235783Skib } 1213235783Skib 1214235783Skib /* Fetch corresponding timestamp for this vblank interval from 1215235783Skib * driver and store it in proper slot of timestamp ringbuffer. 1216235783Skib */ 1217235783Skib 1218235783Skib /* Get current timestamp and count. */ 1219235783Skib vblcount = atomic_read(&dev->_vblank_count[crtc]); 1220235783Skib drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); 1221235783Skib 1222235783Skib /* Compute time difference to timestamp of last vblank */ 1223235783Skib diff_ns = timeval_to_ns(&tvblank) - 1224235783Skib timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); 1225235783Skib 1226235783Skib /* Update vblank timestamp and count if at least 1227235783Skib * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds 1228235783Skib * difference between last stored timestamp and current 1229235783Skib * timestamp. A smaller difference means basically 1230235783Skib * identical timestamps. Happens if this vblank has 1231235783Skib * been already processed and this is a redundant call, 1232235783Skib * e.g., due to spurious vblank interrupts. We need to 1233235783Skib * ignore those for accounting. 1234235783Skib */ 1235235783Skib if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { 1236235783Skib /* Store new timestamp in ringbuffer. */ 1237235783Skib vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; 1238235783Skib 1239235783Skib /* Increment cooked vblank count. This also atomically commits 1240235783Skib * the timestamp computed above. 1241235783Skib */ 1242235783Skib atomic_inc(&dev->_vblank_count[crtc]); 1243235783Skib } else { 1244235783Skib DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", 1245235783Skib crtc, (int) diff_ns); 1246235783Skib } 1247235783Skib 1248235783Skib wakeup(&dev->_vblank_count[crtc]); 1249235783Skib drm_handle_vblank_events(dev, crtc); 1250235783Skib 1251235783Skib mtx_unlock(&dev->vblank_time_lock); 1252235783Skib return true; 1253235783Skib} 1254