/**1* \file drm_irq.c2* IRQ support3*4* \author Rickard E. (Rik) Faith <[email protected]>5* \author Gareth Hughes <[email protected]>6*/78/*9* Created: Fri Mar 19 14:30:16 1999 by [email protected]10*11* Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.12* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.13* All Rights Reserved.14*15* Permission is hereby granted, free of charge, to any person obtaining a16* copy of this software and associated documentation files (the "Software"),17* to deal in the Software without restriction, including without limitation18* the rights to use, copy, modify, merge, publish, distribute, sublicense,19* and/or sell copies of the Software, and to permit persons to whom the20* Software is furnished to do so, subject to the following conditions:21*22* The above copyright notice and this permission notice (including the next23* paragraph) shall be included in all copies or substantial portions of the24* Software.25*26* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR27* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,28* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL29* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR30* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,31* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR32* OTHER DEALINGS IN THE SOFTWARE.33*/3435#include "drmP.h"36#include "drm_trace.h"3738#include <linux/interrupt.h> /* For task queue support */39#include <linux/slab.h>4041#include <linux/vgaarb.h>4243/* Access macro for slots in vblank timestamp ringbuffer. */44#define vblanktimestamp(dev, crtc, count) ( \45(dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \46((count) % DRM_VBLANKTIME_RBSIZE)])4748/* Retry timestamp calculation up to 3 times to satisfy49* drm_timestamp_precision before giving up.50*/51#define DRM_TIMESTAMP_MAXRETRIES 35253/* Threshold in nanoseconds for detection of redundant54* vblank irq in drm_handle_vblank(). 1 msec should be ok.55*/56#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 10000005758/**59* Get interrupt from bus id.60*61* \param inode device inode.62* \param file_priv DRM file private.63* \param cmd command.64* \param arg user argument, pointing to a drm_irq_busid structure.65* \return zero on success or a negative number on failure.66*67* Finds the PCI device with the specified bus id and gets its IRQ number.68* This IOCTL is deprecated, and will now return EINVAL for any busid not equal69* to that of the device that this DRM instance attached to.70*/71int drm_irq_by_busid(struct drm_device *dev, void *data,72struct drm_file *file_priv)73{74struct drm_irq_busid *p = data;7576if (!dev->driver->bus->irq_by_busid)77return -EINVAL;7879if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))80return -EINVAL;8182return dev->driver->bus->irq_by_busid(dev, p);83}8485/*86* Clear vblank timestamp buffer for a crtc.87*/88static void clear_vblank_timestamps(struct drm_device *dev, int crtc)89{90memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,91DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));92}9394/*95* Disable vblank irq's on crtc, make sure that last vblank count96* of hardware and corresponding consistent software vblank counter97* are preserved, even if there are any spurious vblank irq's after98* disable.99*/100static void vblank_disable_and_save(struct drm_device *dev, int crtc)101{102unsigned long irqflags;103u32 vblcount;104s64 diff_ns;105int vblrc;106struct timeval tvblank;107108/* Prevent vblank irq processing while disabling vblank irqs,109* so no updates of timestamps or count can happen after we've110* disabled. Needed to prevent races in case of delayed irq's.111* Disable preemption, so vblank_time_lock is held as short as112* possible, even under a kernel with PREEMPT_RT patches.113*/114preempt_disable();115spin_lock_irqsave(&dev->vblank_time_lock, irqflags);116117dev->driver->disable_vblank(dev, crtc);118dev->vblank_enabled[crtc] = 0;119120/* No further vblank irq's will be processed after121* this point. Get current hardware vblank count and122* vblank timestamp, repeat until they are consistent.123*124* FIXME: There is still a race condition here and in125* drm_update_vblank_count() which can cause off-by-one126* reinitialization of software vblank counter. If gpu127* vblank counter doesn't increment exactly at the leading128* edge of a vblank interval, then we can lose 1 count if129* we happen to execute between start of vblank and the130* delayed gpu counter increment.131*/132do {133dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);134vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);135} while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc));136137/* Compute time difference to stored timestamp of last vblank138* as updated by last invocation of drm_handle_vblank() in vblank irq.139*/140vblcount = atomic_read(&dev->_vblank_count[crtc]);141diff_ns = timeval_to_ns(&tvblank) -142timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));143144/* If there is at least 1 msec difference between the last stored145* timestamp and tvblank, then we are currently executing our146* disable inside a new vblank interval, the tvblank timestamp147* corresponds to this new vblank interval and the irq handler148* for this vblank didn't run yet and won't run due to our disable.149* Therefore we need to do the job of drm_handle_vblank() and150* increment the vblank counter by one to account for this vblank.151*152* Skip this step if there isn't any high precision timestamp153* available. In that case we can't account for this and just154* hope for the best.155*/156if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {157atomic_inc(&dev->_vblank_count[crtc]);158smp_mb__after_atomic_inc();159}160161/* Invalidate all timestamps while vblank irq's are off. */162clear_vblank_timestamps(dev, crtc);163164spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);165preempt_enable();166}167168static void vblank_disable_fn(unsigned long arg)169{170struct drm_device *dev = (struct drm_device *)arg;171unsigned long irqflags;172int i;173174if (!dev->vblank_disable_allowed)175return;176177for (i = 0; i < dev->num_crtcs; i++) {178spin_lock_irqsave(&dev->vbl_lock, irqflags);179if (atomic_read(&dev->vblank_refcount[i]) == 0 &&180dev->vblank_enabled[i]) {181DRM_DEBUG("disabling vblank on crtc %d\n", i);182vblank_disable_and_save(dev, i);183}184spin_unlock_irqrestore(&dev->vbl_lock, irqflags);185}186}187188void drm_vblank_cleanup(struct drm_device *dev)189{190/* Bail if the driver didn't call drm_vblank_init() */191if (dev->num_crtcs == 0)192return;193194del_timer(&dev->vblank_disable_timer);195196vblank_disable_fn((unsigned long)dev);197198kfree(dev->vbl_queue);199kfree(dev->_vblank_count);200kfree(dev->vblank_refcount);201kfree(dev->vblank_enabled);202kfree(dev->last_vblank);203kfree(dev->last_vblank_wait);204kfree(dev->vblank_inmodeset);205kfree(dev->_vblank_time);206207dev->num_crtcs = 0;208}209EXPORT_SYMBOL(drm_vblank_cleanup);210211int drm_vblank_init(struct drm_device *dev, int num_crtcs)212{213int i, ret = -ENOMEM;214215setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,216(unsigned long)dev);217spin_lock_init(&dev->vbl_lock);218spin_lock_init(&dev->vblank_time_lock);219220dev->num_crtcs = num_crtcs;221222dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,223GFP_KERNEL);224if (!dev->vbl_queue)225goto err;226227dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL);228if (!dev->_vblank_count)229goto err;230231dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs,232GFP_KERNEL);233if (!dev->vblank_refcount)234goto err;235236dev->vblank_enabled = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);237if (!dev->vblank_enabled)238goto err;239240dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);241if (!dev->last_vblank)242goto err;243244dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);245if (!dev->last_vblank_wait)246goto err;247248dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);249if (!dev->vblank_inmodeset)250goto err;251252dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,253sizeof(struct timeval), GFP_KERNEL);254if (!dev->_vblank_time)255goto err;256257DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");258259/* Driver specific high-precision vblank timestamping supported? */260if (dev->driver->get_vblank_timestamp)261DRM_INFO("Driver supports precise vblank timestamp query.\n");262else263DRM_INFO("No driver support for vblank timestamp query.\n");264265/* Zero per-crtc vblank stuff */266for (i = 0; i < num_crtcs; i++) {267init_waitqueue_head(&dev->vbl_queue[i]);268atomic_set(&dev->_vblank_count[i], 0);269atomic_set(&dev->vblank_refcount[i], 0);270}271272dev->vblank_disable_allowed = 0;273return 0;274275err:276drm_vblank_cleanup(dev);277return ret;278}279EXPORT_SYMBOL(drm_vblank_init);280281static void drm_irq_vgaarb_nokms(void *cookie, bool state)282{283struct drm_device *dev = cookie;284285if (dev->driver->vgaarb_irq) {286dev->driver->vgaarb_irq(dev, state);287return;288}289290if (!dev->irq_enabled)291return;292293if (state)294dev->driver->irq_uninstall(dev);295else {296dev->driver->irq_preinstall(dev);297dev->driver->irq_postinstall(dev);298}299}300301/**302* Install IRQ handler.303*304* \param dev DRM device.305*306* Initializes the IRQ related data. Installs the handler, calling the driver307* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions308* before and after the installation.309*/310int drm_irq_install(struct drm_device *dev)311{312int ret = 0;313unsigned long sh_flags = 0;314char *irqname;315316if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))317return -EINVAL;318319if (drm_dev_to_irq(dev) == 0)320return -EINVAL;321322mutex_lock(&dev->struct_mutex);323324/* Driver must have been initialized */325if (!dev->dev_private) {326mutex_unlock(&dev->struct_mutex);327return -EINVAL;328}329330if (dev->irq_enabled) {331mutex_unlock(&dev->struct_mutex);332return -EBUSY;333}334dev->irq_enabled = 1;335mutex_unlock(&dev->struct_mutex);336337DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));338339/* Before installing handler */340dev->driver->irq_preinstall(dev);341342/* Install handler */343if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))344sh_flags = IRQF_SHARED;345346if (dev->devname)347irqname = dev->devname;348else349irqname = dev->driver->name;350351ret = request_irq(drm_dev_to_irq(dev), dev->driver->irq_handler,352sh_flags, irqname, dev);353354if (ret < 0) {355mutex_lock(&dev->struct_mutex);356dev->irq_enabled = 0;357mutex_unlock(&dev->struct_mutex);358return ret;359}360361if (!drm_core_check_feature(dev, DRIVER_MODESET))362vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);363364/* After installing handler */365ret = dev->driver->irq_postinstall(dev);366if (ret < 0) {367mutex_lock(&dev->struct_mutex);368dev->irq_enabled = 0;369mutex_unlock(&dev->struct_mutex);370}371372return ret;373}374EXPORT_SYMBOL(drm_irq_install);375376/**377* Uninstall the IRQ handler.378*379* \param dev DRM device.380*381* Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.382*/383int drm_irq_uninstall(struct drm_device *dev)384{385unsigned long irqflags;386int irq_enabled, i;387388if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))389return -EINVAL;390391mutex_lock(&dev->struct_mutex);392irq_enabled = dev->irq_enabled;393dev->irq_enabled = 0;394mutex_unlock(&dev->struct_mutex);395396/*397* Wake up any waiters so they don't hang.398*/399spin_lock_irqsave(&dev->vbl_lock, irqflags);400for (i = 0; i < dev->num_crtcs; i++) {401DRM_WAKEUP(&dev->vbl_queue[i]);402dev->vblank_enabled[i] = 0;403dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i);404}405spin_unlock_irqrestore(&dev->vbl_lock, irqflags);406407if (!irq_enabled)408return -EINVAL;409410DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));411412if (!drm_core_check_feature(dev, DRIVER_MODESET))413vga_client_register(dev->pdev, NULL, NULL, NULL);414415dev->driver->irq_uninstall(dev);416417free_irq(drm_dev_to_irq(dev), dev);418419return 0;420}421EXPORT_SYMBOL(drm_irq_uninstall);422423/**424* IRQ control ioctl.425*426* \param inode device inode.427* \param file_priv DRM file private.428* \param cmd command.429* \param arg user argument, pointing to a drm_control structure.430* \return zero on success or a negative number on failure.431*432* Calls irq_install() or irq_uninstall() according to \p arg.433*/434int drm_control(struct drm_device *dev, void *data,435struct drm_file *file_priv)436{437struct drm_control *ctl = data;438439/* if we haven't irq we fallback for compatibility reasons -440* this used to be a separate function in drm_dma.h441*/442443444switch (ctl->func) {445case DRM_INST_HANDLER:446if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))447return 0;448if (drm_core_check_feature(dev, DRIVER_MODESET))449return 0;450if (dev->if_version < DRM_IF_VERSION(1, 2) &&451ctl->irq != drm_dev_to_irq(dev))452return -EINVAL;453return drm_irq_install(dev);454case DRM_UNINST_HANDLER:455if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))456return 0;457if (drm_core_check_feature(dev, DRIVER_MODESET))458return 0;459return drm_irq_uninstall(dev);460default:461return -EINVAL;462}463}464465/**466* drm_calc_timestamping_constants - Calculate and467* store various constants which are later needed by468* vblank and swap-completion timestamping, e.g, by469* drm_calc_vbltimestamp_from_scanoutpos().470* They are derived from crtc's true scanout timing,471* so they take things like panel scaling or other472* adjustments into account.473*474* @crtc drm_crtc whose timestamp constants should be updated.475*476*/477void drm_calc_timestamping_constants(struct drm_crtc *crtc)478{479s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;480u64 dotclock;481482/* Dot clock in Hz: */483dotclock = (u64) crtc->hwmode.clock * 1000;484485/* Fields of interlaced scanout modes are only halve a frame duration.486* Double the dotclock to get halve the frame-/line-/pixelduration.487*/488if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)489dotclock *= 2;490491/* Valid dotclock? */492if (dotclock > 0) {493/* Convert scanline length in pixels and video dot clock to494* line duration, frame duration and pixel duration in495* nanoseconds:496*/497pixeldur_ns = (s64) div64_u64(1000000000, dotclock);498linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *4991000000000), dotclock);500framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns;501} else502DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",503crtc->base.id);504505crtc->pixeldur_ns = pixeldur_ns;506crtc->linedur_ns = linedur_ns;507crtc->framedur_ns = framedur_ns;508509DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",510crtc->base.id, crtc->hwmode.crtc_htotal,511crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);512DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",513crtc->base.id, (int) dotclock/1000, (int) framedur_ns,514(int) linedur_ns, (int) pixeldur_ns);515}516EXPORT_SYMBOL(drm_calc_timestamping_constants);517518/**519* drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms520* drivers. Implements calculation of exact vblank timestamps from521* given drm_display_mode timings and current video scanout position522* of a crtc. This can be called from within get_vblank_timestamp()523* implementation of a kms driver to implement the actual timestamping.524*525* Should return timestamps conforming to the OML_sync_control OpenML526* extension specification. The timestamp corresponds to the end of527* the vblank interval, aka start of scanout of topmost-leftmost display528* pixel in the following video frame.529*530* Requires support for optional dev->driver->get_scanout_position()531* in kms driver, plus a bit of setup code to provide a drm_display_mode532* that corresponds to the true scanout timing.533*534* The current implementation only handles standard video modes. It535* returns as no operation if a doublescan or interlaced video mode is536* active. Higher level code is expected to handle this.537*538* @dev: DRM device.539* @crtc: Which crtc's vblank timestamp to retrieve.540* @max_error: Desired maximum allowable error in timestamps (nanosecs).541* On return contains true maximum error of timestamp.542* @vblank_time: Pointer to struct timeval which should receive the timestamp.543* @flags: Flags to pass to driver:544* 0 = Default.545* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.546* @refcrtc: drm_crtc* of crtc which defines scanout timing.547*548* Returns negative value on error, failure or if not supported in current549* video mode:550*551* -EINVAL - Invalid crtc.552* -EAGAIN - Temporary unavailable, e.g., called before initial modeset.553* -ENOTSUPP - Function not supported in current display mode.554* -EIO - Failed, e.g., due to failed scanout position query.555*556* Returns or'ed positive status flags on success:557*558* DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.559* DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.560*561*/562int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,563int *max_error,564struct timeval *vblank_time,565unsigned flags,566struct drm_crtc *refcrtc)567{568struct timeval stime, raw_time;569struct drm_display_mode *mode;570int vbl_status, vtotal, vdisplay;571int vpos, hpos, i;572s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;573bool invbl;574575if (crtc < 0 || crtc >= dev->num_crtcs) {576DRM_ERROR("Invalid crtc %d\n", crtc);577return -EINVAL;578}579580/* Scanout position query not supported? Should not happen. */581if (!dev->driver->get_scanout_position) {582DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");583return -EIO;584}585586mode = &refcrtc->hwmode;587vtotal = mode->crtc_vtotal;588vdisplay = mode->crtc_vdisplay;589590/* Durations of frames, lines, pixels in nanoseconds. */591framedur_ns = refcrtc->framedur_ns;592linedur_ns = refcrtc->linedur_ns;593pixeldur_ns = refcrtc->pixeldur_ns;594595/* If mode timing undefined, just return as no-op:596* Happens during initial modesetting of a crtc.597*/598if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {599DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);600return -EAGAIN;601}602603/* Get current scanout position with system timestamp.604* Repeat query up to DRM_TIMESTAMP_MAXRETRIES times605* if single query takes longer than max_error nanoseconds.606*607* This guarantees a tight bound on maximum error if608* code gets preempted or delayed for some reason.609*/610for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) {611/* Disable preemption to make it very likely to612* succeed in the first iteration even on PREEMPT_RT kernel.613*/614preempt_disable();615616/* Get system timestamp before query. */617do_gettimeofday(&stime);618619/* Get vertical and horizontal scanout pos. vpos, hpos. */620vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos);621622/* Get system timestamp after query. */623do_gettimeofday(&raw_time);624625preempt_enable();626627/* Return as no-op if scanout query unsupported or failed. */628if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {629DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",630crtc, vbl_status);631return -EIO;632}633634duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime);635636/* Accept result with < max_error nsecs timing uncertainty. */637if (duration_ns <= (s64) *max_error)638break;639}640641/* Noisy system timing? */642if (i == DRM_TIMESTAMP_MAXRETRIES) {643DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",644crtc, (int) duration_ns/1000, *max_error/1000, i);645}646647/* Return upper bound of timestamp precision error. */648*max_error = (int) duration_ns;649650/* Check if in vblank area:651* vpos is >=0 in video scanout area, but negative652* within vblank area, counting down the number of lines until653* start of scanout.654*/655invbl = vbl_status & DRM_SCANOUTPOS_INVBL;656657/* Convert scanout position into elapsed time at raw_time query658* since start of scanout at first display scanline. delta_ns659* can be negative if start of scanout hasn't happened yet.660*/661delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;662663/* Is vpos outside nominal vblank area, but less than664* 1/100 of a frame height away from start of vblank?665* If so, assume this isn't a massively delayed vblank666* interrupt, but a vblank interrupt that fired a few667* microseconds before true start of vblank. Compensate668* by adding a full frame duration to the final timestamp.669* Happens, e.g., on ATI R500, R600.670*671* We only do this if DRM_CALLED_FROM_VBLIRQ.672*/673if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&674((vdisplay - vpos) < vtotal / 100)) {675delta_ns = delta_ns - framedur_ns;676677/* Signal this correction as "applied". */678vbl_status |= 0x8;679}680681/* Subtract time delta from raw timestamp to get final682* vblank_time timestamp for end of vblank.683*/684*vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);685686DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",687crtc, (int)vbl_status, hpos, vpos,688(long)raw_time.tv_sec, (long)raw_time.tv_usec,689(long)vblank_time->tv_sec, (long)vblank_time->tv_usec,690(int)duration_ns/1000, i);691692vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;693if (invbl)694vbl_status |= DRM_VBLANKTIME_INVBL;695696return vbl_status;697}698EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);699700/**701* drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent702* vblank interval.703*704* @dev: DRM device705* @crtc: which crtc's vblank timestamp to retrieve706* @tvblank: Pointer to target struct timeval which should receive the timestamp707* @flags: Flags to pass to driver:708* 0 = Default.709* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.710*711* Fetches the system timestamp corresponding to the time of the most recent712* vblank interval on specified crtc. May call into kms-driver to713* compute the timestamp with a high-precision GPU specific method.714*715* Returns zero if timestamp originates from uncorrected do_gettimeofday()716* call, i.e., it isn't very precisely locked to the true vblank.717*718* Returns non-zero if timestamp is considered to be very precise.719*/720u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,721struct timeval *tvblank, unsigned flags)722{723int ret = 0;724725/* Define requested maximum error on timestamps (nanoseconds). */726int max_error = (int) drm_timestamp_precision * 1000;727728/* Query driver if possible and precision timestamping enabled. */729if (dev->driver->get_vblank_timestamp && (max_error > 0)) {730ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,731tvblank, flags);732if (ret > 0)733return (u32) ret;734}735736/* GPU high precision timestamp query unsupported or failed.737* Return gettimeofday timestamp as best estimate.738*/739do_gettimeofday(tvblank);740741return 0;742}743EXPORT_SYMBOL(drm_get_last_vbltimestamp);744745/**746* drm_vblank_count - retrieve "cooked" vblank counter value747* @dev: DRM device748* @crtc: which counter to retrieve749*750* Fetches the "cooked" vblank count value that represents the number of751* vblank events since the system was booted, including lost events due to752* modesetting activity.753*/754u32 drm_vblank_count(struct drm_device *dev, int crtc)755{756return atomic_read(&dev->_vblank_count[crtc]);757}758EXPORT_SYMBOL(drm_vblank_count);759760/**761* drm_vblank_count_and_time - retrieve "cooked" vblank counter value762* and the system timestamp corresponding to that vblank counter value.763*764* @dev: DRM device765* @crtc: which counter to retrieve766* @vblanktime: Pointer to struct timeval to receive the vblank timestamp.767*768* Fetches the "cooked" vblank count value that represents the number of769* vblank events since the system was booted, including lost events due to770* modesetting activity. Returns corresponding system timestamp of the time771* of the vblank interval that corresponds to the current value vblank counter772* value.773*/774u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,775struct timeval *vblanktime)776{777u32 cur_vblank;778779/* Read timestamp from slot of _vblank_time ringbuffer780* that corresponds to current vblank count. Retry if781* count has incremented during readout. This works like782* a seqlock.783*/784do {785cur_vblank = atomic_read(&dev->_vblank_count[crtc]);786*vblanktime = vblanktimestamp(dev, crtc, cur_vblank);787smp_rmb();788} while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));789790return cur_vblank;791}792EXPORT_SYMBOL(drm_vblank_count_and_time);793794/**795* drm_update_vblank_count - update the master vblank counter796* @dev: DRM device797* @crtc: counter to update798*799* Call back into the driver to update the appropriate vblank counter800* (specified by @crtc). Deal with wraparound, if it occurred, and801* update the last read value so we can deal with wraparound on the next802* call if necessary.803*804* Only necessary when going from off->on, to account for frames we805* didn't get an interrupt for.806*807* Note: caller must hold dev->vbl_lock since this reads & writes808* device vblank fields.809*/810static void drm_update_vblank_count(struct drm_device *dev, int crtc)811{812u32 cur_vblank, diff, tslot, rc;813struct timeval t_vblank;814815/*816* Interrupts were disabled prior to this call, so deal with counter817* wrap if needed.818* NOTE! It's possible we lost a full dev->max_vblank_count events819* here if the register is small or we had vblank interrupts off for820* a long time.821*822* We repeat the hardware vblank counter & timestamp query until823* we get consistent results. This to prevent races between gpu824* updating its hardware counter while we are retrieving the825* corresponding vblank timestamp.826*/827do {828cur_vblank = dev->driver->get_vblank_counter(dev, crtc);829rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);830} while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));831832/* Deal with counter wrap */833diff = cur_vblank - dev->last_vblank[crtc];834if (cur_vblank < dev->last_vblank[crtc]) {835diff += dev->max_vblank_count;836837DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",838crtc, dev->last_vblank[crtc], cur_vblank, diff);839}840841DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",842crtc, diff);843844/* Reinitialize corresponding vblank timestamp if high-precision query845* available. Skip this step if query unsupported or failed. Will846* reinitialize delayed at next vblank interrupt in that case.847*/848if (rc) {849tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;850vblanktimestamp(dev, crtc, tslot) = t_vblank;851}852853smp_mb__before_atomic_inc();854atomic_add(diff, &dev->_vblank_count[crtc]);855smp_mb__after_atomic_inc();856}857858/**859* drm_vblank_get - get a reference count on vblank events860* @dev: DRM device861* @crtc: which CRTC to own862*863* Acquire a reference count on vblank events to avoid having them disabled864* while in use.865*866* RETURNS867* Zero on success, nonzero on failure.868*/869int drm_vblank_get(struct drm_device *dev, int crtc)870{871unsigned long irqflags, irqflags2;872int ret = 0;873874spin_lock_irqsave(&dev->vbl_lock, irqflags);875/* Going from 0->1 means we have to enable interrupts again */876if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {877/* Disable preemption while holding vblank_time_lock. Do878* it explicitely to guard against PREEMPT_RT kernel.879*/880preempt_disable();881spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);882if (!dev->vblank_enabled[crtc]) {883/* Enable vblank irqs under vblank_time_lock protection.884* All vblank count & timestamp updates are held off885* until we are done reinitializing master counter and886* timestamps. Filtercode in drm_handle_vblank() will887* prevent double-accounting of same vblank interval.888*/889ret = dev->driver->enable_vblank(dev, crtc);890DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",891crtc, ret);892if (ret)893atomic_dec(&dev->vblank_refcount[crtc]);894else {895dev->vblank_enabled[crtc] = 1;896drm_update_vblank_count(dev, crtc);897}898}899spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);900preempt_enable();901} else {902if (!dev->vblank_enabled[crtc]) {903atomic_dec(&dev->vblank_refcount[crtc]);904ret = -EINVAL;905}906}907spin_unlock_irqrestore(&dev->vbl_lock, irqflags);908909return ret;910}911EXPORT_SYMBOL(drm_vblank_get);912913/**914* drm_vblank_put - give up ownership of vblank events915* @dev: DRM device916* @crtc: which counter to give up917*918* Release ownership of a given vblank counter, turning off interrupts919* if possible. Disable interrupts after drm_vblank_offdelay milliseconds.920*/921void drm_vblank_put(struct drm_device *dev, int crtc)922{923BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);924925/* Last user schedules interrupt disable */926if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&927(drm_vblank_offdelay > 0))928mod_timer(&dev->vblank_disable_timer,929jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));930}931EXPORT_SYMBOL(drm_vblank_put);932933void drm_vblank_off(struct drm_device *dev, int crtc)934{935struct drm_pending_vblank_event *e, *t;936struct timeval now;937unsigned long irqflags;938unsigned int seq;939940spin_lock_irqsave(&dev->vbl_lock, irqflags);941vblank_disable_and_save(dev, crtc);942DRM_WAKEUP(&dev->vbl_queue[crtc]);943944/* Send any queued vblank events, lest the natives grow disquiet */945seq = drm_vblank_count_and_time(dev, crtc, &now);946list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {947if (e->pipe != crtc)948continue;949DRM_DEBUG("Sending premature vblank event on disable: \950wanted %d, current %d\n",951e->event.sequence, seq);952953e->event.sequence = seq;954e->event.tv_sec = now.tv_sec;955e->event.tv_usec = now.tv_usec;956drm_vblank_put(dev, e->pipe);957list_move_tail(&e->base.link, &e->base.file_priv->event_list);958wake_up_interruptible(&e->base.file_priv->event_wait);959trace_drm_vblank_event_delivered(e->base.pid, e->pipe,960e->event.sequence);961}962963spin_unlock_irqrestore(&dev->vbl_lock, irqflags);964}965EXPORT_SYMBOL(drm_vblank_off);966967/**968* drm_vblank_pre_modeset - account for vblanks across mode sets969* @dev: DRM device970* @crtc: CRTC in question971* @post: post or pre mode set?972*973* Account for vblank events across mode setting events, which will likely974* reset the hardware frame counter.975*/976void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)977{978/* vblank is not initialized (IRQ not installed ?) */979if (!dev->num_crtcs)980return;981/*982* To avoid all the problems that might happen if interrupts983* were enabled/disabled around or between these calls, we just984* have the kernel take a reference on the CRTC (just once though985* to avoid corrupting the count if multiple, mismatch calls occur),986* so that interrupts remain enabled in the interim.987*/988if (!dev->vblank_inmodeset[crtc]) {989dev->vblank_inmodeset[crtc] = 0x1;990if (drm_vblank_get(dev, crtc) == 0)991dev->vblank_inmodeset[crtc] |= 0x2;992}993}994EXPORT_SYMBOL(drm_vblank_pre_modeset);995996void drm_vblank_post_modeset(struct drm_device *dev, int crtc)997{998unsigned long irqflags;9991000if (dev->vblank_inmodeset[crtc]) {1001spin_lock_irqsave(&dev->vbl_lock, irqflags);1002dev->vblank_disable_allowed = 1;1003spin_unlock_irqrestore(&dev->vbl_lock, irqflags);10041005if (dev->vblank_inmodeset[crtc] & 0x2)1006drm_vblank_put(dev, crtc);10071008dev->vblank_inmodeset[crtc] = 0;1009}1010}1011EXPORT_SYMBOL(drm_vblank_post_modeset);10121013/**1014* drm_modeset_ctl - handle vblank event counter changes across mode switch1015* @DRM_IOCTL_ARGS: standard ioctl arguments1016*1017* Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET1018* ioctls around modesetting so that any lost vblank events are accounted for.1019*1020* Generally the counter will reset across mode sets. If interrupts are1021* enabled around this call, we don't have to do anything since the counter1022* will have already been incremented.1023*/1024int drm_modeset_ctl(struct drm_device *dev, void *data,1025struct drm_file *file_priv)1026{1027struct drm_modeset_ctl *modeset = data;1028int ret = 0;1029unsigned int crtc;10301031/* If drm_vblank_init() hasn't been called yet, just no-op */1032if (!dev->num_crtcs)1033goto out;10341035crtc = modeset->crtc;1036if (crtc >= dev->num_crtcs) {1037ret = -EINVAL;1038goto out;1039}10401041switch (modeset->cmd) {1042case _DRM_PRE_MODESET:1043drm_vblank_pre_modeset(dev, crtc);1044break;1045case _DRM_POST_MODESET:1046drm_vblank_post_modeset(dev, crtc);1047break;1048default:1049ret = -EINVAL;1050break;1051}10521053out:1054return ret;1055}10561057static int drm_queue_vblank_event(struct drm_device *dev, int pipe,1058union drm_wait_vblank *vblwait,1059struct drm_file *file_priv)1060{1061struct drm_pending_vblank_event *e;1062struct timeval now;1063unsigned long flags;1064unsigned int seq;1065int ret;10661067e = kzalloc(sizeof *e, GFP_KERNEL);1068if (e == NULL) {1069ret = -ENOMEM;1070goto err_put;1071}10721073e->pipe = pipe;1074e->base.pid = current->pid;1075e->event.base.type = DRM_EVENT_VBLANK;1076e->event.base.length = sizeof e->event;1077e->event.user_data = vblwait->request.signal;1078e->base.event = &e->event.base;1079e->base.file_priv = file_priv;1080e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;10811082spin_lock_irqsave(&dev->event_lock, flags);10831084if (file_priv->event_space < sizeof e->event) {1085ret = -EBUSY;1086goto err_unlock;1087}10881089file_priv->event_space -= sizeof e->event;1090seq = drm_vblank_count_and_time(dev, pipe, &now);10911092if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&1093(seq - vblwait->request.sequence) <= (1 << 23)) {1094vblwait->request.sequence = seq + 1;1095vblwait->reply.sequence = vblwait->request.sequence;1096}10971098DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",1099vblwait->request.sequence, seq, pipe);11001101trace_drm_vblank_event_queued(current->pid, pipe,1102vblwait->request.sequence);11031104e->event.sequence = vblwait->request.sequence;1105if ((seq - vblwait->request.sequence) <= (1 << 23)) {1106e->event.sequence = seq;1107e->event.tv_sec = now.tv_sec;1108e->event.tv_usec = now.tv_usec;1109drm_vblank_put(dev, pipe);1110list_add_tail(&e->base.link, &e->base.file_priv->event_list);1111wake_up_interruptible(&e->base.file_priv->event_wait);1112vblwait->reply.sequence = seq;1113trace_drm_vblank_event_delivered(current->pid, pipe,1114vblwait->request.sequence);1115} else {1116list_add_tail(&e->base.link, &dev->vblank_event_list);1117vblwait->reply.sequence = vblwait->request.sequence;1118}11191120spin_unlock_irqrestore(&dev->event_lock, flags);11211122return 0;11231124err_unlock:1125spin_unlock_irqrestore(&dev->event_lock, flags);1126kfree(e);1127err_put:1128drm_vblank_put(dev, pipe);1129return ret;1130}11311132/**1133* Wait for VBLANK.1134*1135* \param inode device inode.1136* \param file_priv DRM file private.1137* \param cmd command.1138* \param data user argument, pointing to a drm_wait_vblank structure.1139* \return zero on success or a negative number on failure.1140*1141* This function enables the vblank interrupt on the pipe requested, then1142* sleeps waiting for the requested sequence number to occur, and drops1143* the vblank interrupt refcount afterwards. (vblank irq disable follows that1144* after a timeout with no further vblank waits scheduled).1145*/1146int drm_wait_vblank(struct drm_device *dev, void *data,1147struct drm_file *file_priv)1148{1149union drm_wait_vblank *vblwait = data;1150int ret = 0;1151unsigned int flags, seq, crtc, high_crtc;11521153if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))1154return -EINVAL;11551156if (vblwait->request.type & _DRM_VBLANK_SIGNAL)1157return -EINVAL;11581159if (vblwait->request.type &1160~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |1161_DRM_VBLANK_HIGH_CRTC_MASK)) {1162DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",1163vblwait->request.type,1164(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |1165_DRM_VBLANK_HIGH_CRTC_MASK));1166return -EINVAL;1167}11681169flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;1170high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);1171if (high_crtc)1172crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT;1173else1174crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;1175if (crtc >= dev->num_crtcs)1176return -EINVAL;11771178ret = drm_vblank_get(dev, crtc);1179if (ret) {1180DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);1181return ret;1182}1183seq = drm_vblank_count(dev, crtc);11841185switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {1186case _DRM_VBLANK_RELATIVE:1187vblwait->request.sequence += seq;1188vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;1189case _DRM_VBLANK_ABSOLUTE:1190break;1191default:1192ret = -EINVAL;1193goto done;1194}11951196if (flags & _DRM_VBLANK_EVENT)1197return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);11981199if ((flags & _DRM_VBLANK_NEXTONMISS) &&1200(seq - vblwait->request.sequence) <= (1<<23)) {1201vblwait->request.sequence = seq + 1;1202}12031204DRM_DEBUG("waiting on vblank count %d, crtc %d\n",1205vblwait->request.sequence, crtc);1206dev->last_vblank_wait[crtc] = vblwait->request.sequence;1207DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,1208(((drm_vblank_count(dev, crtc) -1209vblwait->request.sequence) <= (1 << 23)) ||1210!dev->irq_enabled));12111212if (ret != -EINTR) {1213struct timeval now;12141215vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now);1216vblwait->reply.tval_sec = now.tv_sec;1217vblwait->reply.tval_usec = now.tv_usec;12181219DRM_DEBUG("returning %d to client\n",1220vblwait->reply.sequence);1221} else {1222DRM_DEBUG("vblank wait interrupted by signal\n");1223}12241225done:1226drm_vblank_put(dev, crtc);1227return ret;1228}12291230void drm_handle_vblank_events(struct drm_device *dev, int crtc)1231{1232struct drm_pending_vblank_event *e, *t;1233struct timeval now;1234unsigned long flags;1235unsigned int seq;12361237seq = drm_vblank_count_and_time(dev, crtc, &now);12381239spin_lock_irqsave(&dev->event_lock, flags);12401241list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {1242if (e->pipe != crtc)1243continue;1244if ((seq - e->event.sequence) > (1<<23))1245continue;12461247DRM_DEBUG("vblank event on %d, current %d\n",1248e->event.sequence, seq);12491250e->event.sequence = seq;1251e->event.tv_sec = now.tv_sec;1252e->event.tv_usec = now.tv_usec;1253drm_vblank_put(dev, e->pipe);1254list_move_tail(&e->base.link, &e->base.file_priv->event_list);1255wake_up_interruptible(&e->base.file_priv->event_wait);1256trace_drm_vblank_event_delivered(e->base.pid, e->pipe,1257e->event.sequence);1258}12591260spin_unlock_irqrestore(&dev->event_lock, flags);12611262trace_drm_vblank_event(crtc, seq);1263}12641265/**1266* drm_handle_vblank - handle a vblank event1267* @dev: DRM device1268* @crtc: where this event occurred1269*1270* Drivers should call this routine in their vblank interrupt handlers to1271* update the vblank counter and send any signals that may be pending.1272*/1273bool drm_handle_vblank(struct drm_device *dev, int crtc)1274{1275u32 vblcount;1276s64 diff_ns;1277struct timeval tvblank;1278unsigned long irqflags;12791280if (!dev->num_crtcs)1281return false;12821283/* Need timestamp lock to prevent concurrent execution with1284* vblank enable/disable, as this would cause inconsistent1285* or corrupted timestamps and vblank counts.1286*/1287spin_lock_irqsave(&dev->vblank_time_lock, irqflags);12881289/* Vblank irq handling disabled. Nothing to do. */1290if (!dev->vblank_enabled[crtc]) {1291spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);1292return false;1293}12941295/* Fetch corresponding timestamp for this vblank interval from1296* driver and store it in proper slot of timestamp ringbuffer.1297*/12981299/* Get current timestamp and count. */1300vblcount = atomic_read(&dev->_vblank_count[crtc]);1301drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);13021303/* Compute time difference to timestamp of last vblank */1304diff_ns = timeval_to_ns(&tvblank) -1305timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));13061307/* Update vblank timestamp and count if at least1308* DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds1309* difference between last stored timestamp and current1310* timestamp. A smaller difference means basically1311* identical timestamps. Happens if this vblank has1312* been already processed and this is a redundant call,1313* e.g., due to spurious vblank interrupts. We need to1314* ignore those for accounting.1315*/1316if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {1317/* Store new timestamp in ringbuffer. */1318vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;13191320/* Increment cooked vblank count. This also atomically commits1321* the timestamp computed above.1322*/1323smp_mb__before_atomic_inc();1324atomic_inc(&dev->_vblank_count[crtc]);1325smp_mb__after_atomic_inc();1326} else {1327DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",1328crtc, (int) diff_ns);1329}13301331DRM_WAKEUP(&dev->vbl_queue[crtc]);1332drm_handle_vblank_events(dev, crtc);13331334spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);1335return true;1336}1337EXPORT_SYMBOL(drm_handle_vblank);133813391340