From: Sourab Gupta <sourab.gupta@xxxxxxxxx> Using MMIO based flips on VLV for Media power well residency optimization. The blitter ring is currently being used just for command streamer based flip calls. For pure 3D workloads, with MMIO flips, there will be no use of blitter ring and this will ensure the 100% residency for Media well. v2: The MMIO flips now use the interrupt driven mechanism for issuing the flips when target seqno is reached. (Incorporating Ville's idea) v3: Rebasing on latest code. Code restructuring after incorporating Damien's comments Signed-off-by: Sourab Gupta <sourab.gupta@xxxxxxxxx> Signed-off-by: Akash Goel <akash.goel@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 7 ++ drivers/gpu/drm/i915/i915_irq.c | 2 + drivers/gpu/drm/i915/intel_display.c | 124 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 7 ++ 5 files changed, 141 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4e0a26a..bca3c5a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1569,6 +1569,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->backlight_lock); spin_lock_init(&dev_priv->uncore.lock); spin_lock_init(&dev_priv->mm.object_stat_lock); + spin_lock_init(&dev_priv->mmio_flip_lock); mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->modeset_restore_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3f62be0..678d31d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1621,6 +1621,10 @@ typedef struct drm_i915_private { struct i915_dri1_state dri1; /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; + + /* protects the mmio flip data */ + spinlock_t mmio_flip_lock; + } drm_i915_private_t; static inline struct drm_i915_private *to_i915(const struct drm_device *dev) @@ -2657,6 +2661,9 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data, int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +void intel_notify_mmio_flip(struct drm_device *dev, + struct intel_ring_buffer *ring); + /* overlay */ extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4b4aeb3..ad26abe 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1080,6 +1080,8 @@ static void notify_ring(struct drm_device *dev, trace_i915_gem_request_complete(ring); + intel_notify_mmio_flip(dev, ring); + wake_up_all(&ring->irq_queue); i915_queue_hangcheck(dev); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e4ea8d..19004bf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8782,6 +8782,125 @@ err: return ret; } +static int intel_do_mmio_flip(struct drm_device *dev, + struct drm_crtc *crtc) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + + intel_crtc = to_intel_crtc(crtc); + + intel_mark_page_flip_active(intel_crtc); + return dev_priv->display.update_primary_plane(crtc, crtc->fb, 0, 0); +} + +static bool intel_postpone_flip(struct drm_i915_gem_object *obj) +{ + int ret; + if (!obj->ring) + return false; + + if (i915_seqno_passed(obj->ring->get_seqno(obj->ring, false), + obj->last_write_seqno)) + return false; + + if (obj->last_write_seqno == obj->ring->outstanding_lazy_seqno) { + ret = i915_add_request(obj->ring, NULL); + if (WARN_ON(ret)) + return false; + } + + if (WARN_ON(!obj->ring->irq_get(obj->ring))) + return false; + + return true; +} + +void intel_notify_mmio_flip(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + struct intel_mmio_flip *mmio_flip_data; + unsigned long irq_flags; + u32 seqno; + enum pipe pipe; + + BUG_ON(!ring); + + seqno = ring->get_seqno(ring, false); + + spin_lock_irqsave(&dev_priv->mmio_flip_lock, irq_flags); + for_each_pipe(pipe) { + crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + intel_crtc = to_intel_crtc(crtc); + mmio_flip_data = &intel_crtc->mmio_flip_data; + if ((mmio_flip_data->seqno != 0) && + (ring->id == mmio_flip_data->ring_id) && + (seqno >= mmio_flip_data->seqno)) { + intel_do_mmio_flip(dev, crtc); + mmio_flip_data->seqno = 0; + ring->irq_put(ring); + } + } + + spin_unlock_irqrestore(&dev_priv->mmio_flip_lock, irq_flags); +} + +/* Using MMIO based flips starting from VLV, for Media power well + * residency optimization. The other alternative of having Render + * ring based flip calls is not being used, as the performance + * (FPS) of certain 3D Apps was getting severly affected. + */ +static int intel_gen7_queue_mmio_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_i915_gem_object *obj, + uint32_t flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long irq_flags; + int ret; + + ret = intel_pin_and_fence_fb_obj(dev, obj, obj->ring); + if (ret) + goto err; + + switch (intel_crtc->plane) { + case PLANE_A: + case PLANE_B: + case PLANE_C: + break; + default: + WARN_ONCE(1, "unknown plane in flip command\n"); + ret = -ENODEV; + goto err_unpin; + } + + if (!intel_postpone_flip(obj)) { + ret = intel_do_mmio_flip(dev, crtc); + return ret; + } + + spin_lock_irqsave(&dev_priv->mmio_flip_lock, irq_flags); + intel_crtc->mmio_flip_data.seqno = obj->last_write_seqno; + intel_crtc->mmio_flip_data.ring_id = obj->ring->id; + spin_unlock_irqrestore(&dev_priv->mmio_flip_lock, irq_flags); + + /* Double check to catch cases where irq fired before + * mmio flip data was ready + */ + intel_notify_mmio_flip(dev, obj->ring); + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: + return ret; +} + static int intel_gen7_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -10577,6 +10696,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; } + if (IS_VALLEYVIEW(dev)) + intel_crtc->mmio_flip_data.seqno = 0; BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL); @@ -11107,6 +11228,9 @@ static void intel_init_display(struct drm_device *dev) } intel_panel_init_backlight_funcs(dev); + + if (IS_VALLEYVIEW(dev)) + dev_priv->display.queue_flip = intel_gen7_queue_mmio_flip; } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fa99104..f0b26a1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -344,6 +344,11 @@ struct intel_pipe_wm { bool fbc_wm_enabled; }; +struct intel_mmio_flip { + u32 seqno; + u32 ring_id; +}; + struct intel_crtc { struct drm_crtc base; enum pipe pipe; @@ -395,6 +400,8 @@ struct intel_crtc { /* watermarks currently being used */ struct intel_pipe_wm active; } wm; + + struct intel_mmio_flip mmio_flip_data; }; struct intel_plane_wm_parameters { -- 1.8.5.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx