[Intel-gfx] [PATCH 5/6] drm/i915: Grab modeset locks for GPU rest on pre-ctg
Ville Syrjälä
ville.syrjala at linux.intel.com
Fri Nov 21 22:10:31 CET 2014
On Fri, Nov 21, 2014 at 09:49:21PM +0100, Daniel Vetter wrote:
> On Fri, Nov 21, 2014 at 09:54:29PM +0200, ville.syrjala at linux.intel.com wrote:
> > From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> >
> > On gen4 and earlier the GPU reset also resets the display, so we should
> > protect against concurrent modeset operations. Grab all the modeset locks
> > around the entire GPU reset dance, remebering first ti dislogde any
> > pending page flip to make sure we don't deadlock. Any pageflip coming
> > in between these two steps should fail anyway due to reset_in_progress,
> > so this should be safe.
> >
> > This fixes a lot of failed asserts in the modeset code when there's a
> > modeset racing with the reset. Naturally the asserts aren't happy when
> > the expected state has disappeared.
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> Two comments on this one, otherwise looks good (well didn't bother to
> check the new reset register frobbing).
> -Daniel
>
> > ---
> > drivers/gpu/drm/i915/i915_drv.c | 19 -------
> > drivers/gpu/drm/i915/i915_irq.c | 5 +-
> > drivers/gpu/drm/i915/intel_display.c | 96 ++++++++++++++++++++++++++++++------
> > drivers/gpu/drm/i915/intel_drv.h | 3 +-
> > 4 files changed, 86 insertions(+), 37 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> > index 5066fd1..1e9c136 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.c
> > +++ b/drivers/gpu/drm/i915/i915_drv.c
> > @@ -880,25 +880,6 @@ int i915_reset(struct drm_device *dev)
> > */
> > if (INTEL_INFO(dev)->gen > 5)
> > intel_reset_gt_powersave(dev);
> > -
> > -
> > - if (IS_GEN3(dev) || (IS_GEN4(dev) && !IS_G4X(dev))) {
> > - intel_runtime_pm_disable_interrupts(dev_priv);
> > - intel_runtime_pm_enable_interrupts(dev_priv);
> > -
> > - intel_modeset_init_hw(dev);
> > -
> > - spin_lock_irq(&dev_priv->irq_lock);
> > - if (dev_priv->display.hpd_irq_setup)
> > - dev_priv->display.hpd_irq_setup(dev);
> > - spin_unlock_irq(&dev_priv->irq_lock);
> > -
> > - drm_modeset_lock_all(dev);
> > - intel_modeset_setup_hw_state(dev, true);
> > - drm_modeset_unlock_all(dev);
> > -
> > - intel_hpd_init(dev_priv);
> > - }
> > } else {
> > mutex_unlock(&dev->struct_mutex);
> > }
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 5908580d..8887674 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -2428,6 +2428,9 @@ static void i915_error_work_func(struct work_struct *work)
> > * simulated reset via debugs, so get an RPM reference.
> > */
> > intel_runtime_pm_get(dev_priv);
> > +
> > + intel_prepare_reset(dev);
> > +
> > /*
> > * All state reset _must_ be completed before we update the
> > * reset counter, for otherwise waiters might miss the reset
> > @@ -2436,7 +2439,7 @@ static void i915_error_work_func(struct work_struct *work)
> > */
> > ret = i915_reset(dev);
> >
> > - intel_display_handle_reset(dev);
> > + intel_finish_reset(dev);
> >
> > intel_runtime_pm_put(dev_priv);
> >
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 3218455..8329f7c 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -2765,25 +2765,10 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
> > return 0;
> > }
> >
> > -void intel_display_handle_reset(struct drm_device *dev)
> > +static void intel_complete_page_flips(struct drm_device *dev)
> > {
> > - struct drm_i915_private *dev_priv = dev->dev_private;
> > struct drm_crtc *crtc;
> >
> > - /*
> > - * Flips in the rings have been nuked by the reset,
> > - * so complete all pending flips so that user space
> > - * will get its events and not get stuck.
> > - *
> > - * Also update the base address of all primary
> > - * planes to the the last fb to make sure we're
> > - * showing the correct fb after a reset.
> > - *
> > - * Need to make two loops over the crtcs so that we
> > - * don't try to grab a crtc mutex before the
> > - * pending_flip_queue really got woken up.
> > - */
> > -
> > for_each_crtc(dev, crtc) {
> > struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > enum plane plane = intel_crtc->plane;
> > @@ -2791,6 +2776,12 @@ void intel_display_handle_reset(struct drm_device *dev)
> > intel_prepare_page_flip(dev, plane);
> > intel_finish_page_flip_plane(dev, plane);
> > }
> > +}
> > +
> > +static void intel_update_primary_planes(struct drm_device *dev)
> > +{
> > + struct drm_i915_private *dev_priv = dev->dev_private;
> > + struct drm_crtc *crtc;
> >
> > for_each_crtc(dev, crtc) {
> > struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> > @@ -2810,6 +2801,79 @@ void intel_display_handle_reset(struct drm_device *dev)
> > }
> > }
> >
> > +void intel_prepare_reset(struct drm_device *dev)
> > +{
> > + if (!drm_core_check_feature(dev, DRIVER_MODESET))
> > + return;
>
> ums just officially died please remove. Same for the one below.
okey dokey
>
> > +
> > + /*
> > + * Flips in the rings will be nuked by the reset,
> > + * so complete all pending flips so that user space
> > + * will get its events and not get stuck.
> > + *
> > + * Old platforms will also reset the display, so we
> > + * need to grab the modeset locks around the reset.
> > + * But in order to do that we must let any pending
> > + * page flip wait complete since the waiters may be
> > + * holding some modeset locks.
> > + */
> > + intel_complete_page_flips(dev);
>
> Is this really required? We complete them afterwards, and all the pageflip
> waiters I've found do check for gpu hangs and abort the pageflip wait.
> That's already required since the mmio flip might go missing, and thus far
> we've only completed the flip _after_ having reset the gpu and gem state
> (and grabbed dev->struct_mutex).
Hmm. Yeah, just waking them up ought to be sufficient to dislodge
things. And we already do that before scheduling the error work, but
after setting the reset_in_progress flag, which is very much critical
here. So I guess I could just move the complete pending flips bit to
intel_finish_reset().
But then I do wonder a bit why I originally needed to add the unlocked
page flip complete before the locked .update_plane() call. Did we miss
a wakeup somewhere or did we not abort pending flip waits on reset?
>
> > +
> > + /* no reset support for gen2 */
> > + if (IS_GEN2(dev))
> > + return;
> > +
> > + /* reset doesn't touch the display */
> > + if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
> > + return;
> > +
> > + drm_modeset_lock_all(dev);
> > +}
> > +
> > +void intel_finish_reset(struct drm_device *dev)
> > +{
> > + struct drm_i915_private *dev_priv = to_i915(dev);
> > +
> > + if (!drm_core_check_feature(dev, DRIVER_MODESET))
> > + return;
> > +
> > + /* no reset support for gen2 */
> > + if (IS_GEN2(dev))
> > + return;
> > +
> > + /* reset doesn't touch the display */
> > + if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev)) {
> > + /*
> > + * Flips in the rings have been nuked by the reset,
> > + * so update the base address of all primary
> > + * planes to the the last fb to make sure we're
> > + * showing the correct fb after a reset.
> > + */
> > + intel_update_primary_planes(dev);
> > + return;
> > + }
> > +
> > + /*
> > + * The display has been reset as well,
> > + * so need a full re-initialization.
> > + */
> > + intel_runtime_pm_disable_interrupts(dev_priv);
> > + intel_runtime_pm_enable_interrupts(dev_priv);
> > +
> > + intel_modeset_init_hw(dev);
> > +
> > + spin_lock_irq(&dev_priv->irq_lock);
> > + if (dev_priv->display.hpd_irq_setup)
> > + dev_priv->display.hpd_irq_setup(dev);
> > + spin_unlock_irq(&dev_priv->irq_lock);
> > +
> > + intel_modeset_setup_hw_state(dev, true);
> > +
> > + intel_hpd_init(dev_priv);
> > +
> > + drm_modeset_unlock_all(dev);
> > +}
> > +
> > static int
> > intel_finish_fb(struct drm_framebuffer *old_fb)
> > {
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index f0a46ec..25fdbb1 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -958,7 +958,8 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y,
> > unsigned int tiling_mode,
> > unsigned int bpp,
> > unsigned int pitch);
> > -void intel_display_handle_reset(struct drm_device *dev);
> > +void intel_prepare_reset(struct drm_device *dev);
> > +void intel_finish_reset(struct drm_device *dev);
> > void hsw_enable_pc8(struct drm_i915_private *dev_priv);
> > void hsw_disable_pc8(struct drm_i915_private *dev_priv);
> > void intel_dp_get_m_n(struct intel_crtc *crtc,
> > --
> > 2.0.4
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
--
Ville Syrjälä
Intel OTC
More information about the Intel-gfx
mailing list