aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-08 07:22:42 -0400
committerKeith Packard <keithp@keithp.com>2011-07-08 13:23:17 -0400
commit1630fe754c83b3e57efa51c85f1a21e612a63a0e (patch)
tree54b122ad648f655b6f9db1012bad3a9996b161ea /drivers/gpu
parent7782de3bd671657674e7baba854f0fd43e9f86bc (diff)
drm/i915: Perform intel_enable_fbc() from a delayed task
In order to accommodate the requirements of re-enabling FBC after page-flipping, but to avoid doing so and incurring the cost of a wait for vblank in the middle of a page-flip sequence, we defer the actual enablement by 50ms. If any request to disable FBC arrive within that interval, the enablement is cancelled and we are saved from blocking on the wait. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c83
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h7
3 files changed, 90 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 56cb1c4fe73e..3154b3dfd804 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -266,6 +266,7 @@ enum intel_pch {
266#define QUIRK_PIPEA_FORCE (1<<0) 266#define QUIRK_PIPEA_FORCE (1<<0)
267 267
268struct intel_fbdev; 268struct intel_fbdev;
269struct intel_fbc_work;
269 270
270typedef struct drm_i915_private { 271typedef struct drm_i915_private {
271 struct drm_device *dev; 272 struct drm_device *dev;
@@ -335,6 +336,7 @@ typedef struct drm_i915_private {
335 int cfb_fence; 336 int cfb_fence;
336 int cfb_plane; 337 int cfb_plane;
337 int cfb_y; 338 int cfb_y;
339 struct intel_fbc_work *fbc_work;
338 340
339 struct intel_opregion opregion; 341 struct intel_opregion opregion;
340 342
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f0788a97801e..df2839c59b74 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1636,20 +1636,96 @@ bool intel_fbc_enabled(struct drm_device *dev)
1636 return dev_priv->display.fbc_enabled(dev); 1636 return dev_priv->display.fbc_enabled(dev);
1637} 1637}
1638 1638
1639static void intel_fbc_work_fn(struct work_struct *__work)
1640{
1641 struct intel_fbc_work *work =
1642 container_of(to_delayed_work(__work),
1643 struct intel_fbc_work, work);
1644 struct drm_device *dev = work->crtc->dev;
1645 struct drm_i915_private *dev_priv = dev->dev_private;
1646
1647 mutex_lock(&dev->struct_mutex);
1648 if (work == dev_priv->fbc_work) {
1649 /* Double check that we haven't switched fb without cancelling
1650 * the prior work.
1651 */
1652 if (work->crtc->fb == work->fb)
1653 dev_priv->display.enable_fbc(work->crtc,
1654 work->interval);
1655
1656 dev_priv->fbc_work = NULL;
1657 }
1658 mutex_unlock(&dev->struct_mutex);
1659
1660 kfree(work);
1661}
1662
1663static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
1664{
1665 if (dev_priv->fbc_work == NULL)
1666 return;
1667
1668 DRM_DEBUG_KMS("cancelling pending FBC enable\n");
1669
1670 /* Synchronisation is provided by struct_mutex and checking of
1671 * dev_priv->fbc_work, so we can perform the cancellation
1672 * entirely asynchronously.
1673 */
1674 if (cancel_delayed_work(&dev_priv->fbc_work->work))
1675 /* tasklet was killed before being run, clean up */
1676 kfree(dev_priv->fbc_work);
1677
1678 /* Mark the work as no longer wanted so that if it does
1679 * wake-up (because the work was already running and waiting
1680 * for our mutex), it will discover that is no longer
1681 * necessary to run.
1682 */
1683 dev_priv->fbc_work = NULL;
1684}
1685
1639static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) 1686static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
1640{ 1687{
1641 struct drm_i915_private *dev_priv = crtc->dev->dev_private; 1688 struct intel_fbc_work *work;
1689 struct drm_device *dev = crtc->dev;
1690 struct drm_i915_private *dev_priv = dev->dev_private;
1642 1691
1643 if (!dev_priv->display.enable_fbc) 1692 if (!dev_priv->display.enable_fbc)
1644 return; 1693 return;
1645 1694
1646 dev_priv->display.enable_fbc(crtc, interval); 1695 intel_cancel_fbc_work(dev_priv);
1696
1697 work = kzalloc(sizeof *work, GFP_KERNEL);
1698 if (work == NULL) {
1699 dev_priv->display.enable_fbc(crtc, interval);
1700 return;
1701 }
1702
1703 work->crtc = crtc;
1704 work->fb = crtc->fb;
1705 work->interval = interval;
1706 INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
1707
1708 dev_priv->fbc_work = work;
1709
1710 DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
1711
1712 /* Delay the actual enabling to let pageflipping cease and the
1713 * display to settle before starting the compression.
1714 *
1715 * A more complicated solution would involve tracking vblanks
1716 * following the termination of the page-flipping sequence
1717 * and indeed performing the enable as a co-routine and not
1718 * waiting synchronously upon the vblank.
1719 */
1720 schedule_delayed_work(&work->work, msecs_to_jiffies(50));
1647} 1721}
1648 1722
1649void intel_disable_fbc(struct drm_device *dev) 1723void intel_disable_fbc(struct drm_device *dev)
1650{ 1724{
1651 struct drm_i915_private *dev_priv = dev->dev_private; 1725 struct drm_i915_private *dev_priv = dev->dev_private;
1652 1726
1727 intel_cancel_fbc_work(dev_priv);
1728
1653 if (!dev_priv->display.disable_fbc) 1729 if (!dev_priv->display.disable_fbc)
1654 return; 1730 return;
1655 1731
@@ -8227,6 +8303,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
8227 drm_irq_uninstall(dev); 8303 drm_irq_uninstall(dev);
8228 cancel_work_sync(&dev_priv->hotplug_work); 8304 cancel_work_sync(&dev_priv->hotplug_work);
8229 8305
8306 /* flush any delayed tasks or pending work */
8307 flush_scheduled_work();
8308
8230 /* Shut off idle work before the crtcs get freed. */ 8309 /* Shut off idle work before the crtcs get freed. */
8231 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 8310 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
8232 intel_crtc = to_intel_crtc(crtc); 8311 intel_crtc = to_intel_crtc(crtc);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7ec48d864577..6e990f9760ef 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -234,6 +234,13 @@ struct intel_unpin_work {
234 bool enable_stall_check; 234 bool enable_stall_check;
235}; 235};
236 236
237struct intel_fbc_work {
238 struct delayed_work work;
239 struct drm_crtc *crtc;
240 struct drm_framebuffer *fb;
241 int interval;
242};
243
237int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); 244int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
238extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); 245extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
239 246