2014-05-08 21:41:51 +07:00
|
|
|
/*
|
|
|
|
* drm_irq.c IRQ and vblank support
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
|
|
|
* \author Gareth Hughes <gareth@valinux.com>
|
2017-05-31 16:21:46 +07:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
|
|
|
|
*
|
|
|
|
* Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
|
|
|
|
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2019-05-27 00:35:35 +07:00
|
|
|
#include <linux/export.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/interrupt.h> /* For task queue support */
|
2019-05-27 00:35:35 +07:00
|
|
|
#include <linux/pci.h>
|
2009-09-21 11:33:58 +07:00
|
|
|
#include <linux/vgaarb.h>
|
2019-05-27 00:35:35 +07:00
|
|
|
|
|
|
|
#include <drm/drm.h>
|
|
|
|
#include <drm/drm_device.h>
|
|
|
|
#include <drm/drm_drv.h>
|
|
|
|
#include <drm/drm_irq.h>
|
|
|
|
#include <drm/drm_print.h>
|
|
|
|
#include <drm/drm_vblank.h>
|
drm/vblank: Add support for precise vblank timestamping.
The DRI2 swap & sync implementation needs precise
vblank counts and precise timestamps corresponding
to those vblank counts. For conformance to the OpenML
OML_sync_control extension specification the DRM
timestamp associated with a vblank count should
correspond to the start of video scanout of the first
scanline of the video frame following the vblank
interval for that vblank count.
Therefore we need to carry around precise timestamps
for vblanks. Currently the DRM and KMS drivers generate
timestamps ad-hoc via do_gettimeofday() in some
places. The resulting timestamps are sometimes not
very precise due to interrupt handling delays, they
don't conform to OML_sync_control and some are wrong,
as they aren't taken synchronized to the vblank.
This patch implements support inside the drm core
for precise and robust timestamping. It consists
of the following interrelated pieces.
1. Vblank timestamp caching:
A per-crtc ringbuffer stores the most recent vblank
timestamps corresponding to vblank counts.
The ringbuffer can be read out lock-free via the
accessor function:
struct timeval timestamp;
vblankcount = drm_vblank_count_and_time(dev, crtcid, ×tamp).
The function returns the current vblank count and
the corresponding timestamp for start of video
scanout following the vblank interval. It can be
used anywhere between enclosing drm_vblank_get(dev, crtcid)
and drm_vblank_put(dev,crtcid) statements. It is used
inside the drmWaitVblank ioctl and in the vblank event
queueing and handling. It should be used by kms drivers for
timestamping of bufferswap completion.
The timestamp ringbuffer is reinitialized each time
vblank irq's get reenabled in drm_vblank_get()/
drm_update_vblank_count(). It is invalidated when
vblank irq's get disabled.
The ringbuffer is updated inside drm_handle_vblank()
at each vblank irq.
2. Calculation of precise vblank timestamps:
drm_get_last_vbltimestamp() is used to compute the
timestamp for the end of the most recent vblank (if
inside active scanout), or the expected end of the
current vblank interval (if called inside a vblank
interval). The function calls into a new optional kms
driver entry point dev->driver->get_vblank_timestamp()
which is supposed to provide the precise timestamp.
If a kms driver doesn't implement the entry point or
if the call fails, a simple do_gettimeofday() timestamp
is returned as crude approximation of the true vblank time.
A new drm module parameter drm.timestamp_precision_usec
allows to disable high precision timestamps (if set to
zero) or to specify the maximum acceptable error in
the timestamps in microseconds.
Kms drivers could implement their get_vblank_timestamp()
function in a gpu specific way, as long as returned
timestamps conform to OML_sync_control, e.g., by use
of gpu specific hardware timestamps.
Optionally, kms drivers can simply wrap and use the new
utility function drm_calc_vbltimestamp_from_scanoutpos().
This function calls a new optional kms driver function
dev->driver->get_scanout_position() which returns the
current horizontal and vertical video scanout position
of the crtc. The scanout position together with the
drm_display_timing of the current video mode is used
to calculate elapsed time relative to start of active scanout
for the current video frame. This elapsed time is subtracted
from the current do_gettimeofday() time to get the timestamp
corresponding to start of video scanout. Currently
non-interlaced, non-doublescan video modes, with or
without panel scaling are handled correctly. Interlaced/
doublescan modes are tbd in a future patch.
3. Filtering of redundant vblank irq's and removal of
some race-conditions in the vblank irq enable/disable path:
Some gpu's (e.g., Radeon R500/R600) send spurious vblank
irq's outside the vblank if vblank irq's get reenabled.
These get detected by use of the vblank timestamps and
filtered out to avoid miscounting of vblanks.
Some race-conditions between the vblank irq enable/disable
functions, the vblank irq handler and the gpu itself (updating
its hardware vblank counter in the "wrong" moment) are
fixed inside vblank_disable_and_save() and
drm_update_vblank_count() by use of the vblank timestamps and
a new spinlock dev->vblank_time_lock.
The time until vblank irq disable is now configurable via
a new drm module parameter drm.vblankoffdelay to allow
experimentation with timeouts that are much shorter than
the current 5 seconds and should allow longer vblank off
periods for better power savings.
Followup patches will use these new functions to
implement precise timestamping for the intel and radeon
kms drivers.
Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2010-10-23 09:20:23 +07:00
|
|
|
|
2017-05-31 16:21:46 +07:00
|
|
|
#include "drm_internal.h"
|
2008-10-01 02:14:26 +07:00
|
|
|
|
2017-05-31 16:22:53 +07:00
|
|
|
/**
|
|
|
|
* DOC: irq helpers
|
|
|
|
*
|
|
|
|
* The DRM core provides very simple support helpers to enable IRQ handling on a
|
|
|
|
* device through the drm_irq_install() and drm_irq_uninstall() functions. This
|
|
|
|
* only supports devices with a single interrupt on the main device stored in
|
|
|
|
* &drm_device.dev and set as the device paramter in drm_dev_alloc().
|
|
|
|
*
|
|
|
|
* These IRQ helpers are strictly optional. Drivers which roll their own only
|
|
|
|
* need to set &drm_device.irq_enabled to signal the DRM core that vblank
|
|
|
|
* interrupts are working. Since these helpers don't automatically clean up the
|
|
|
|
* requested interrupt like e.g. devm_request_irq() they're not really
|
|
|
|
* recommended.
|
|
|
|
*/
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/**
|
2014-05-08 21:41:51 +07:00
|
|
|
* drm_irq_install - install IRQ handler
|
|
|
|
* @dev: DRM device
|
|
|
|
* @irq: IRQ number to install the handler for
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
2008-10-01 02:14:26 +07:00
|
|
|
* Initializes the IRQ related data. Installs the handler, calling the driver
|
2017-05-31 16:22:53 +07:00
|
|
|
* &drm_driver.irq_preinstall and &drm_driver.irq_postinstall functions before
|
|
|
|
* and after the installation.
|
2014-05-08 21:41:51 +07:00
|
|
|
*
|
|
|
|
* This is the simplified helper interface provided for drivers with no special
|
|
|
|
* needs. Drivers which need to install interrupt handlers for multiple
|
2017-01-25 13:26:47 +07:00
|
|
|
* interrupts must instead set &drm_device.irq_enabled to signal the DRM core
|
2014-05-08 21:41:51 +07:00
|
|
|
* that vblank interrupts are available.
|
|
|
|
*
|
2017-05-31 16:22:53 +07:00
|
|
|
* @irq must match the interrupt number that would be passed to request_irq(),
|
|
|
|
* if called directly instead of using this helper function.
|
|
|
|
*
|
|
|
|
* &drm_driver.irq_handler is called to handle the registered interrupt.
|
|
|
|
*
|
2014-05-08 21:41:51 +07:00
|
|
|
* Returns:
|
|
|
|
* Zero on success or a negative error code on failure.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2013-11-04 03:09:27 +07:00
|
|
|
int drm_irq_install(struct drm_device *dev, int irq)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2012-05-17 18:27:21 +07:00
|
|
|
int ret;
|
2005-09-25 11:28:13 +07:00
|
|
|
unsigned long sh_flags = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-12-16 17:21:15 +07:00
|
|
|
if (irq == 0)
|
2005-04-17 05:20:36 +07:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-11-04 02:27:05 +07:00
|
|
|
if (dev->irq_enabled)
|
2005-04-17 05:20:36 +07:00
|
|
|
return -EBUSY;
|
2013-10-04 18:53:37 +07:00
|
|
|
dev->irq_enabled = true;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-12-16 17:21:15 +07:00
|
|
|
DRM_DEBUG("irq=%d\n", irq);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2005-09-25 11:28:13 +07:00
|
|
|
/* Before installing handler */
|
2011-08-04 12:41:01 +07:00
|
|
|
if (dev->driver->irq_preinstall)
|
|
|
|
dev->driver->irq_preinstall(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2019-01-29 17:42:48 +07:00
|
|
|
/* PCI devices require shared interrupts. */
|
|
|
|
if (dev->pdev)
|
2006-07-02 09:29:34 +07:00
|
|
|
sh_flags = IRQF_SHARED;
|
2005-09-25 11:28:13 +07:00
|
|
|
|
2013-12-16 17:21:15 +07:00
|
|
|
ret = request_irq(irq, dev->driver->irq_handler,
|
2013-11-04 03:48:48 +07:00
|
|
|
sh_flags, dev->driver->name, dev);
|
2008-09-16 05:00:33 +07:00
|
|
|
|
2005-09-25 11:28:13 +07:00
|
|
|
if (ret < 0) {
|
2013-10-04 18:53:37 +07:00
|
|
|
dev->irq_enabled = false;
|
2005-04-17 05:20:36 +07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-09-25 11:28:13 +07:00
|
|
|
/* After installing handler */
|
2011-08-04 12:41:01 +07:00
|
|
|
if (dev->driver->irq_postinstall)
|
|
|
|
ret = dev->driver->irq_postinstall(dev);
|
|
|
|
|
2008-10-01 02:14:26 +07:00
|
|
|
if (ret < 0) {
|
2013-10-04 18:53:37 +07:00
|
|
|
dev->irq_enabled = false;
|
2016-08-04 02:11:10 +07:00
|
|
|
if (drm_core_check_feature(dev, DRIVER_LEGACY))
|
2011-08-04 12:41:00 +07:00
|
|
|
vga_client_register(dev->pdev, NULL, NULL, NULL);
|
2013-12-16 17:21:15 +07:00
|
|
|
free_irq(irq, dev);
|
|
|
|
} else {
|
|
|
|
dev->irq = irq;
|
2008-10-01 02:14:26 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-10-01 02:14:26 +07:00
|
|
|
return ret;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2008-10-01 02:14:26 +07:00
|
|
|
EXPORT_SYMBOL(drm_irq_install);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/**
|
2014-05-08 21:41:51 +07:00
|
|
|
* drm_irq_uninstall - uninstall the IRQ handler
|
|
|
|
* @dev: DRM device
|
|
|
|
*
|
2017-05-31 16:22:53 +07:00
|
|
|
* Calls the driver's &drm_driver.irq_uninstall function and unregisters the IRQ
|
|
|
|
* handler. This should only be called by drivers which used drm_irq_install()
|
|
|
|
* to set up their interrupt handler. Other drivers must only reset
|
2017-01-25 13:26:47 +07:00
|
|
|
* &drm_device.irq_enabled to false.
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
2014-05-08 21:41:51 +07:00
|
|
|
* Note that for kernel modesetting drivers it is a bug if this function fails.
|
|
|
|
* The sanity checks are only to catch buggy user modesetting drivers which call
|
|
|
|
* the same function through an ioctl.
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
2014-05-08 21:41:51 +07:00
|
|
|
* Returns:
|
|
|
|
* Zero on success or a negative error code on failure.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
drm/vblank: Add support for precise vblank timestamping.
The DRI2 swap & sync implementation needs precise
vblank counts and precise timestamps corresponding
to those vblank counts. For conformance to the OpenML
OML_sync_control extension specification the DRM
timestamp associated with a vblank count should
correspond to the start of video scanout of the first
scanline of the video frame following the vblank
interval for that vblank count.
Therefore we need to carry around precise timestamps
for vblanks. Currently the DRM and KMS drivers generate
timestamps ad-hoc via do_gettimeofday() in some
places. The resulting timestamps are sometimes not
very precise due to interrupt handling delays, they
don't conform to OML_sync_control and some are wrong,
as they aren't taken synchronized to the vblank.
This patch implements support inside the drm core
for precise and robust timestamping. It consists
of the following interrelated pieces.
1. Vblank timestamp caching:
A per-crtc ringbuffer stores the most recent vblank
timestamps corresponding to vblank counts.
The ringbuffer can be read out lock-free via the
accessor function:
struct timeval timestamp;
vblankcount = drm_vblank_count_and_time(dev, crtcid, ×tamp).
The function returns the current vblank count and
the corresponding timestamp for start of video
scanout following the vblank interval. It can be
used anywhere between enclosing drm_vblank_get(dev, crtcid)
and drm_vblank_put(dev,crtcid) statements. It is used
inside the drmWaitVblank ioctl and in the vblank event
queueing and handling. It should be used by kms drivers for
timestamping of bufferswap completion.
The timestamp ringbuffer is reinitialized each time
vblank irq's get reenabled in drm_vblank_get()/
drm_update_vblank_count(). It is invalidated when
vblank irq's get disabled.
The ringbuffer is updated inside drm_handle_vblank()
at each vblank irq.
2. Calculation of precise vblank timestamps:
drm_get_last_vbltimestamp() is used to compute the
timestamp for the end of the most recent vblank (if
inside active scanout), or the expected end of the
current vblank interval (if called inside a vblank
interval). The function calls into a new optional kms
driver entry point dev->driver->get_vblank_timestamp()
which is supposed to provide the precise timestamp.
If a kms driver doesn't implement the entry point or
if the call fails, a simple do_gettimeofday() timestamp
is returned as crude approximation of the true vblank time.
A new drm module parameter drm.timestamp_precision_usec
allows to disable high precision timestamps (if set to
zero) or to specify the maximum acceptable error in
the timestamps in microseconds.
Kms drivers could implement their get_vblank_timestamp()
function in a gpu specific way, as long as returned
timestamps conform to OML_sync_control, e.g., by use
of gpu specific hardware timestamps.
Optionally, kms drivers can simply wrap and use the new
utility function drm_calc_vbltimestamp_from_scanoutpos().
This function calls a new optional kms driver function
dev->driver->get_scanout_position() which returns the
current horizontal and vertical video scanout position
of the crtc. The scanout position together with the
drm_display_timing of the current video mode is used
to calculate elapsed time relative to start of active scanout
for the current video frame. This elapsed time is subtracted
from the current do_gettimeofday() time to get the timestamp
corresponding to start of video scanout. Currently
non-interlaced, non-doublescan video modes, with or
without panel scaling are handled correctly. Interlaced/
doublescan modes are tbd in a future patch.
3. Filtering of redundant vblank irq's and removal of
some race-conditions in the vblank irq enable/disable path:
Some gpu's (e.g., Radeon R500/R600) send spurious vblank
irq's outside the vblank if vblank irq's get reenabled.
These get detected by use of the vblank timestamps and
filtered out to avoid miscounting of vblanks.
Some race-conditions between the vblank irq enable/disable
functions, the vblank irq handler and the gpu itself (updating
its hardware vblank counter in the "wrong" moment) are
fixed inside vblank_disable_and_save() and
drm_update_vblank_count() by use of the vblank timestamps and
a new spinlock dev->vblank_time_lock.
The time until vblank irq disable is now configurable via
a new drm module parameter drm.vblankoffdelay to allow
experimentation with timeouts that are much shorter than
the current 5 seconds and should allow longer vblank off
periods for better power savings.
Followup patches will use these new functions to
implement precise timestamping for the intel and radeon
kms drivers.
Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2010-10-23 09:20:23 +07:00
|
|
|
int drm_irq_uninstall(struct drm_device *dev)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2009-01-07 01:21:24 +07:00
|
|
|
unsigned long irqflags;
|
2013-10-04 18:53:37 +07:00
|
|
|
bool irq_enabled;
|
|
|
|
int i;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
irq_enabled = dev->irq_enabled;
|
2013-10-04 18:53:37 +07:00
|
|
|
dev->irq_enabled = false;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2009-01-07 01:21:24 +07:00
|
|
|
/*
|
2015-02-22 21:11:19 +07:00
|
|
|
* Wake up any waiters so they don't hang. This is just to paper over
|
2016-06-24 17:15:37 +07:00
|
|
|
* issues for UMS drivers which aren't in full control of their
|
2015-02-22 21:11:19 +07:00
|
|
|
* vblank/irq handling. KMS drivers must ensure that vblanks are all
|
|
|
|
* disabled when uninstalling the irq handler.
|
2009-01-07 01:21:24 +07:00
|
|
|
*/
|
2020-05-27 18:11:34 +07:00
|
|
|
if (drm_dev_has_vblank(dev)) {
|
2011-07-04 09:52:27 +07:00
|
|
|
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
|
|
|
for (i = 0; i < dev->num_crtcs; i++) {
|
2014-08-06 18:49:50 +07:00
|
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[i];
|
|
|
|
|
2015-02-22 21:11:19 +07:00
|
|
|
if (!vblank->enabled)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
|
|
|
|
|
2017-05-31 16:21:46 +07:00
|
|
|
drm_vblank_disable_and_save(dev, i);
|
2014-08-06 18:49:50 +07:00
|
|
|
wake_up(&vblank->queue);
|
2011-07-04 09:52:27 +07:00
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
2009-01-07 01:21:24 +07:00
|
|
|
}
|
|
|
|
|
2005-09-25 11:28:13 +07:00
|
|
|
if (!irq_enabled)
|
2005-04-17 05:20:36 +07:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-12-16 17:21:15 +07:00
|
|
|
DRM_DEBUG("irq=%d\n", dev->irq);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2016-08-04 02:11:10 +07:00
|
|
|
if (drm_core_check_feature(dev, DRIVER_LEGACY))
|
2009-09-21 11:33:58 +07:00
|
|
|
vga_client_register(dev->pdev, NULL, NULL, NULL);
|
|
|
|
|
2011-08-04 12:41:01 +07:00
|
|
|
if (dev->driver->irq_uninstall)
|
|
|
|
dev->driver->irq_uninstall(dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-12-16 17:21:15 +07:00
|
|
|
free_irq(dev->irq, dev);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(drm_irq_uninstall);
|
|
|
|
|
2019-04-18 14:10:40 +07:00
|
|
|
#if IS_ENABLED(CONFIG_DRM_LEGACY)
|
2016-12-14 06:08:02 +07:00
|
|
|
int drm_legacy_irq_control(struct drm_device *dev, void *data,
|
|
|
|
struct drm_file *file_priv)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2007-09-03 09:06:45 +07:00
|
|
|
struct drm_control *ctl = data;
|
2013-11-04 03:09:15 +07:00
|
|
|
int ret = 0, irq;
|
2005-09-25 11:28:13 +07:00
|
|
|
|
drm/vblank: Add support for precise vblank timestamping.
The DRI2 swap & sync implementation needs precise
vblank counts and precise timestamps corresponding
to those vblank counts. For conformance to the OpenML
OML_sync_control extension specification the DRM
timestamp associated with a vblank count should
correspond to the start of video scanout of the first
scanline of the video frame following the vblank
interval for that vblank count.
Therefore we need to carry around precise timestamps
for vblanks. Currently the DRM and KMS drivers generate
timestamps ad-hoc via do_gettimeofday() in some
places. The resulting timestamps are sometimes not
very precise due to interrupt handling delays, they
don't conform to OML_sync_control and some are wrong,
as they aren't taken synchronized to the vblank.
This patch implements support inside the drm core
for precise and robust timestamping. It consists
of the following interrelated pieces.
1. Vblank timestamp caching:
A per-crtc ringbuffer stores the most recent vblank
timestamps corresponding to vblank counts.
The ringbuffer can be read out lock-free via the
accessor function:
struct timeval timestamp;
vblankcount = drm_vblank_count_and_time(dev, crtcid, ×tamp).
The function returns the current vblank count and
the corresponding timestamp for start of video
scanout following the vblank interval. It can be
used anywhere between enclosing drm_vblank_get(dev, crtcid)
and drm_vblank_put(dev,crtcid) statements. It is used
inside the drmWaitVblank ioctl and in the vblank event
queueing and handling. It should be used by kms drivers for
timestamping of bufferswap completion.
The timestamp ringbuffer is reinitialized each time
vblank irq's get reenabled in drm_vblank_get()/
drm_update_vblank_count(). It is invalidated when
vblank irq's get disabled.
The ringbuffer is updated inside drm_handle_vblank()
at each vblank irq.
2. Calculation of precise vblank timestamps:
drm_get_last_vbltimestamp() is used to compute the
timestamp for the end of the most recent vblank (if
inside active scanout), or the expected end of the
current vblank interval (if called inside a vblank
interval). The function calls into a new optional kms
driver entry point dev->driver->get_vblank_timestamp()
which is supposed to provide the precise timestamp.
If a kms driver doesn't implement the entry point or
if the call fails, a simple do_gettimeofday() timestamp
is returned as crude approximation of the true vblank time.
A new drm module parameter drm.timestamp_precision_usec
allows to disable high precision timestamps (if set to
zero) or to specify the maximum acceptable error in
the timestamps in microseconds.
Kms drivers could implement their get_vblank_timestamp()
function in a gpu specific way, as long as returned
timestamps conform to OML_sync_control, e.g., by use
of gpu specific hardware timestamps.
Optionally, kms drivers can simply wrap and use the new
utility function drm_calc_vbltimestamp_from_scanoutpos().
This function calls a new optional kms driver function
dev->driver->get_scanout_position() which returns the
current horizontal and vertical video scanout position
of the crtc. The scanout position together with the
drm_display_timing of the current video mode is used
to calculate elapsed time relative to start of active scanout
for the current video frame. This elapsed time is subtracted
from the current do_gettimeofday() time to get the timestamp
corresponding to start of video scanout. Currently
non-interlaced, non-doublescan video modes, with or
without panel scaling are handled correctly. Interlaced/
doublescan modes are tbd in a future patch.
3. Filtering of redundant vblank irq's and removal of
some race-conditions in the vblank irq enable/disable path:
Some gpu's (e.g., Radeon R500/R600) send spurious vblank
irq's outside the vblank if vblank irq's get reenabled.
These get detected by use of the vblank timestamps and
filtered out to avoid miscounting of vblanks.
Some race-conditions between the vblank irq enable/disable
functions, the vblank irq handler and the gpu itself (updating
its hardware vblank counter in the "wrong" moment) are
fixed inside vblank_disable_and_save() and
drm_update_vblank_count() by use of the vblank timestamps and
a new spinlock dev->vblank_time_lock.
The time until vblank irq disable is now configurable via
a new drm module parameter drm.vblankoffdelay to allow
experimentation with timeouts that are much shorter than
the current 5 seconds and should allow longer vblank off
periods for better power savings.
Followup patches will use these new functions to
implement precise timestamping for the intel and radeon
kms drivers.
Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2010-10-23 09:20:23 +07:00
|
|
|
/* if we haven't irq we fallback for compatibility reasons -
|
|
|
|
* this used to be a separate function in drm_dma.h
|
|
|
|
*/
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-11-04 02:02:50 +07:00
|
|
|
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
|
|
|
return 0;
|
2016-08-04 02:11:10 +07:00
|
|
|
if (!drm_core_check_feature(dev, DRIVER_LEGACY))
|
2013-11-04 02:02:50 +07:00
|
|
|
return 0;
|
2016-06-24 17:15:37 +07:00
|
|
|
/* UMS was only ever supported on pci devices. */
|
2013-11-04 02:02:50 +07:00
|
|
|
if (WARN_ON(!dev->pdev))
|
|
|
|
return -EINVAL;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2007-09-03 09:06:45 +07:00
|
|
|
switch (ctl->func) {
|
2005-04-17 05:20:36 +07:00
|
|
|
case DRM_INST_HANDLER:
|
2013-11-04 03:09:15 +07:00
|
|
|
irq = dev->pdev->irq;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
|
2013-11-04 03:09:15 +07:00
|
|
|
ctl->irq != irq)
|
2005-04-17 05:20:36 +07:00
|
|
|
return -EINVAL;
|
2013-11-04 02:27:05 +07:00
|
|
|
mutex_lock(&dev->struct_mutex);
|
2013-11-04 03:09:27 +07:00
|
|
|
ret = drm_irq_install(dev, irq);
|
2013-11-04 02:27:05 +07:00
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
|
|
|
|
return ret;
|
2005-04-17 05:20:36 +07:00
|
|
|
case DRM_UNINST_HANDLER:
|
2013-11-04 02:27:05 +07:00
|
|
|
mutex_lock(&dev->struct_mutex);
|
|
|
|
ret = drm_irq_uninstall(dev);
|
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
|
|
|
|
return ret;
|
2005-04-17 05:20:36 +07:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
2019-04-18 14:10:40 +07:00
|
|
|
#endif
|