aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-07-21 07:31:41 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-07-25 12:23:56 -0400
commitf047e395ddc9da6c307a10629a237502e627ed85 (patch)
tree36a445f1d0bdf1bf37321d55ebfda84475c34b1c /drivers/gpu/drm/i915/intel_display.c
parenta7b9761d0a2ded58170ffb4d423ff3d7228103f4 (diff)
drm/i915: Avoid concurrent access when marking the device as idle/busy
As suggested by Daniel, rip out the independent timers for device and crtc busyness and integrate the manual powermanagement of the display engine into the GEM core and its request tracking. The benefits are that the code is a lot smaller, fewer moving parts and should fit more neatly into the overall activity tracking of the driver. v2: Complete overhaul and removal of the racy timers and workers. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c146
1 files changed, 22 insertions, 124 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 93d9934ba328..b463829b92eb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5860,46 +5860,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
5860 return mode; 5860 return mode;
5861} 5861}
5862 5862
5863#define GPU_IDLE_TIMEOUT 500 /* ms */
5864
5865/* When this timer fires, we've been idle for awhile */
5866static void intel_gpu_idle_timer(unsigned long arg)
5867{
5868 struct drm_device *dev = (struct drm_device *)arg;
5869 drm_i915_private_t *dev_priv = dev->dev_private;
5870
5871 if (!list_empty(&dev_priv->mm.active_list)) {
5872 /* Still processing requests, so just re-arm the timer. */
5873 mod_timer(&dev_priv->idle_timer, jiffies +
5874 msecs_to_jiffies(GPU_IDLE_TIMEOUT));
5875 return;
5876 }
5877
5878 dev_priv->busy = false;
5879 queue_work(dev_priv->wq, &dev_priv->idle_work);
5880}
5881
5882#define CRTC_IDLE_TIMEOUT 1000 /* ms */
5883
5884static void intel_crtc_idle_timer(unsigned long arg)
5885{
5886 struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
5887 struct drm_crtc *crtc = &intel_crtc->base;
5888 drm_i915_private_t *dev_priv = crtc->dev->dev_private;
5889 struct intel_framebuffer *intel_fb;
5890
5891 intel_fb = to_intel_framebuffer(crtc->fb);
5892 if (intel_fb && intel_fb->obj->active) {
5893 /* The framebuffer is still being accessed by the GPU. */
5894 mod_timer(&intel_crtc->idle_timer, jiffies +
5895 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
5896 return;
5897 }
5898
5899 intel_crtc->busy = false;
5900 queue_work(dev_priv->wq, &dev_priv->idle_work);
5901}
5902
5903static void intel_increase_pllclock(struct drm_crtc *crtc) 5863static void intel_increase_pllclock(struct drm_crtc *crtc)
5904{ 5864{
5905 struct drm_device *dev = crtc->dev; 5865 struct drm_device *dev = crtc->dev;
@@ -5929,10 +5889,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
5929 if (dpll & DISPLAY_RATE_SELECT_FPA1) 5889 if (dpll & DISPLAY_RATE_SELECT_FPA1)
5930 DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); 5890 DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
5931 } 5891 }
5932
5933 /* Schedule downclock */
5934 mod_timer(&intel_crtc->idle_timer, jiffies +
5935 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
5936} 5892}
5937 5893
5938static void intel_decrease_pllclock(struct drm_crtc *crtc) 5894static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -5971,89 +5927,48 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
5971 5927
5972} 5928}
5973 5929
5974/** 5930void intel_mark_busy(struct drm_device *dev)
5975 * intel_idle_update - adjust clocks for idleness 5931{
5976 * @work: work struct 5932 intel_sanitize_pm(dev);
5977 * 5933 i915_update_gfx_val(dev->dev_private);
5978 * Either the GPU or display (or both) went idle. Check the busy status 5934}
5979 * here and adjust the CRTC and GPU clocks as necessary. 5935
5980 */ 5936void intel_mark_idle(struct drm_device *dev)
5981static void intel_idle_update(struct work_struct *work)
5982{ 5937{
5983 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 5938 intel_sanitize_pm(dev);
5984 idle_work); 5939}
5985 struct drm_device *dev = dev_priv->dev; 5940
5941void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
5942{
5943 struct drm_device *dev = obj->base.dev;
5986 struct drm_crtc *crtc; 5944 struct drm_crtc *crtc;
5987 struct intel_crtc *intel_crtc;
5988 5945
5989 if (!i915_powersave) 5946 if (!i915_powersave)
5990 return; 5947 return;
5991 5948
5992 mutex_lock(&dev->struct_mutex);
5993
5994 i915_update_gfx_val(dev_priv);
5995
5996 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 5949 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
5997 /* Skip inactive CRTCs */
5998 if (!crtc->fb) 5950 if (!crtc->fb)
5999 continue; 5951 continue;
6000 5952
6001 intel_crtc = to_intel_crtc(crtc); 5953 if (to_intel_framebuffer(crtc->fb)->obj == obj)
6002 if (!intel_crtc->busy) 5954 intel_increase_pllclock(crtc);
6003 intel_decrease_pllclock(crtc);
6004 } 5955 }
6005
6006
6007 mutex_unlock(&dev->struct_mutex);
6008} 5956}
6009 5957
6010/** 5958void intel_mark_fb_idle(struct drm_i915_gem_object *obj)
6011 * intel_mark_busy - mark the GPU and possibly the display busy
6012 * @dev: drm device
6013 * @obj: object we're operating on
6014 *
6015 * Callers can use this function to indicate that the GPU is busy processing
6016 * commands. If @obj matches one of the CRTC objects (i.e. it's a scanout
6017 * buffer), we'll also mark the display as busy, so we know to increase its
6018 * clock frequency.
6019 */
6020void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
6021{ 5959{
6022 drm_i915_private_t *dev_priv = dev->dev_private; 5960 struct drm_device *dev = obj->base.dev;
6023 struct drm_crtc *crtc = NULL; 5961 struct drm_crtc *crtc;
6024 struct intel_framebuffer *intel_fb;
6025 struct intel_crtc *intel_crtc;
6026
6027 if (!drm_core_check_feature(dev, DRIVER_MODESET))
6028 return;
6029
6030 if (!dev_priv->busy) {
6031 intel_sanitize_pm(dev);
6032 dev_priv->busy = true;
6033 } else
6034 mod_timer(&dev_priv->idle_timer, jiffies +
6035 msecs_to_jiffies(GPU_IDLE_TIMEOUT));
6036 5962
6037 if (obj == NULL) 5963 if (!i915_powersave)
6038 return; 5964 return;
6039 5965
6040 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 5966 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
6041 if (!crtc->fb) 5967 if (!crtc->fb)
6042 continue; 5968 continue;
6043 5969
6044 intel_crtc = to_intel_crtc(crtc); 5970 if (to_intel_framebuffer(crtc->fb)->obj == obj)
6045 intel_fb = to_intel_framebuffer(crtc->fb); 5971 intel_decrease_pllclock(crtc);
6046 if (intel_fb->obj == obj) {
6047 if (!intel_crtc->busy) {
6048 /* Non-busy -> busy, upclock */
6049 intel_increase_pllclock(crtc);
6050 intel_crtc->busy = true;
6051 } else {
6052 /* Busy -> busy, put off timer */
6053 mod_timer(&intel_crtc->idle_timer, jiffies +
6054 msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
6055 }
6056 }
6057 } 5972 }
6058} 5973}
6059 5974
@@ -6512,7 +6427,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
6512 goto cleanup_pending; 6427 goto cleanup_pending;
6513 6428
6514 intel_disable_fbc(dev); 6429 intel_disable_fbc(dev);
6515 intel_mark_busy(dev, obj); 6430 intel_mark_fb_busy(obj);
6516 mutex_unlock(&dev->struct_mutex); 6431 mutex_unlock(&dev->struct_mutex);
6517 6432
6518 trace_i915_flip_request(intel_crtc->plane, obj); 6433 trace_i915_flip_request(intel_crtc->plane, obj);
@@ -6678,11 +6593,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
6678 } 6593 }
6679 6594
6680 drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); 6595 drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
6681
6682 intel_crtc->busy = false;
6683
6684 setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
6685 (unsigned long)intel_crtc);
6686} 6596}
6687 6597
6688int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, 6598int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
@@ -7265,10 +7175,6 @@ void intel_modeset_init(struct drm_device *dev)
7265 /* Just disable it once at startup */ 7175 /* Just disable it once at startup */
7266 i915_disable_vga(dev); 7176 i915_disable_vga(dev);
7267 intel_setup_outputs(dev); 7177 intel_setup_outputs(dev);
7268
7269 INIT_WORK(&dev_priv->idle_work, intel_idle_update);
7270 setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
7271 (unsigned long)dev);
7272} 7178}
7273 7179
7274void intel_modeset_gem_init(struct drm_device *dev) 7180void intel_modeset_gem_init(struct drm_device *dev)
@@ -7319,14 +7225,6 @@ void intel_modeset_cleanup(struct drm_device *dev)
7319 /* flush any delayed tasks or pending work */ 7225 /* flush any delayed tasks or pending work */
7320 flush_scheduled_work(); 7226 flush_scheduled_work();
7321 7227
7322 /* Shut off idle work before the crtcs get freed. */
7323 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
7324 intel_crtc = to_intel_crtc(crtc);
7325 del_timer_sync(&intel_crtc->idle_timer);
7326 }
7327 del_timer_sync(&dev_priv->idle_timer);
7328 cancel_work_sync(&dev_priv->idle_work);
7329
7330 drm_mode_config_cleanup(dev); 7228 drm_mode_config_cleanup(dev);
7331} 7229}
7332 7230