public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Cc: intel-gfx@lists.freedesktop.org, shuang.he@linux.intel.com
Subject: Re: [PATCH 3/8] drm/i915: Add infrastructure for choosing DPLLs before disabling crtcs
Date: Wed, 22 Oct 2014 11:33:21 +0300	[thread overview]
Message-ID: <20141022083321.GV4284@intel.com> (raw)
In-Reply-To: <1413896529-32443-4-git-send-email-ander.conselvan.de.oliveira@intel.com>

On Tue, Oct 21, 2014 at 04:02:04PM +0300, Ander Conselvan de Oliveira wrote:
> It is possible for a mode set to fail if there aren't shared DPLLS that
> match the new configuration requirement or other errors in clock
> computation. If that step is executed after disabling crtcs, in the
> failure case the hardware configuration is changed and needs to be
> restored. Doing those things early will allow the mode set to fail
> before actually touching the hardware.
> 
> Follow up patches will convert different platforms to use the new
> infrastructure.
> 
> Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h      |   3 +
>  drivers/gpu/drm/i915/intel_ddi.c     |   2 +
>  drivers/gpu/drm/i915/intel_display.c | 125 +++++++++++++++++++++++++++--------
>  3 files changed, 102 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index d7412d9..5b2464f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -233,6 +233,8 @@ struct intel_shared_dpll_config {
>  
>  struct intel_shared_dpll {
>  	struct intel_shared_dpll_config config;
> +	struct intel_shared_dpll_config *new_config;
> +
>  	int  active; /* count of number of active CRTCs (i.e. DPMS on) */
>  	bool on; /* is the PLL actually active? Disabled during modeset */
>  	const char *name;
> @@ -480,6 +482,7 @@ struct drm_i915_display_funcs {
>  				struct intel_crtc_config *);
>  	void (*get_plane_config)(struct intel_crtc *,
>  				 struct intel_plane_config *);
> +	int (*crtc_compute_clock)(struct intel_crtc *crtc);
>  	int (*crtc_mode_set)(struct intel_crtc *crtc,
>  			     int x, int y,
>  			     struct drm_framebuffer *old_fb);
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 5915a07..7b8c4b8 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1375,6 +1375,8 @@ static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
>  	dev_priv->num_shared_dpll = 2;
>  
>  	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
> +		dev_priv->shared_dplls[i].new_config =
> +			&dev_priv->shared_dplls[i].config;
>  		dev_priv->shared_dplls[i].id = i;
>  		dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
>  		dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable;
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index cdaf8ef..f2f7e8f 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -3851,15 +3851,9 @@ void intel_put_shared_dpll(struct intel_crtc *crtc)
>  struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
>  {
>  	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> -	struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
> +	struct intel_shared_dpll *pll;
>  	enum intel_dpll_id i;
>  
> -	if (pll) {
> -		DRM_DEBUG_KMS("CRTC:%d dropping existing %s\n",
> -			      crtc->base.base.id, pll->name);
> -		intel_put_shared_dpll(crtc);
> -	}
> -
>  	if (HAS_PCH_IBX(dev_priv->dev)) {
>  		/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
>  		i = (enum intel_dpll_id) crtc->pipe;
> @@ -3868,7 +3862,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
>  		DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
>  			      crtc->base.base.id, pll->name);
>  
> -		WARN_ON(pll->config.crtc_mask);
> +		WARN_ON(pll->new_config->crtc_mask);
>  
>  		goto found;
>  	}
> @@ -3877,17 +3871,16 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
>  		pll = &dev_priv->shared_dplls[i];
>  
>  		/* Only want to check enabled timings first */
> -		if (pll->config.crtc_mask == 0)
> +		if (pll->new_config->crtc_mask == 0)
>  			continue;
>  
> -		if (memcmp(&crtc->config.dpll_hw_state,
> -			   &pll->config.hw_state,
> -			   sizeof(pll->config.hw_state)) == 0) {
> -			DRM_DEBUG_KMS("CRTC:%d sharing existing %s "
> -				      "(crtc_mask 0x%08x, active %d)\n",
> +		if (memcmp(&crtc->new_config->dpll_hw_state,
> +			   &pll->new_config->hw_state,
> +			   sizeof(pll->new_config->hw_state)) == 0) {
> +			DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
>  				      crtc->base.base.id, pll->name,
> -				      pll->config.crtc_mask, pll->active);
> -
> +				      pll->new_config->crtc_mask,
> +				      pll->active);
>  			goto found;
>  		}
>  	}
> @@ -3895,7 +3888,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
>  	/* Ok no matching timings, maybe there's a free one? */
>  	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
>  		pll = &dev_priv->shared_dplls[i];
> -		if (pll->config.crtc_mask == 0) {
> +		if (pll->new_config->crtc_mask == 0) {
>  			DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
>  				      crtc->base.base.id, pll->name);
>  			goto found;
> @@ -3905,18 +3898,64 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
>  	return NULL;
>  
>  found:
> -	if (pll->config.crtc_mask == 0)
> -		pll->config.hw_state = crtc->config.dpll_hw_state;
> +	if (pll->new_config->crtc_mask == 0)
> +		pll->new_config->hw_state = crtc->new_config->dpll_hw_state;
>  
> -	crtc->config.shared_dpll = i;
> +	crtc->new_config->shared_dpll = i;
>  	DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
>  			 pipe_name(crtc->pipe));
>  
> -	pll->config.crtc_mask |= 1 << crtc->pipe;
> +	pll->new_config->crtc_mask |= 1 << crtc->pipe;
>  
>  	return pll;
>  }
>  
> +/**
> + * intel_shared_dpll_start_config - start a new PLL staged config
> + * @dev_priv: DRM device
> + * @clear_pipes: mask of pipes that will have their PLLs freed
> + *
> + * Starts a new PLL staged config, copying the current config but
> + * releasing the references of pipes specified in clear_pipes.
> + */
> +static int intel_shared_dpll_start_config(struct drm_i915_private *dev_priv,
> +					  unsigned clear_pipes)
> +{
> +	struct intel_shared_dpll *pll;
> +	enum intel_dpll_id i;
> +
> +	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
> +		pll = &dev_priv->shared_dplls[i];
> +
> +		pll->new_config = kmalloc(sizeof(*pll->new_config),
> +					  GFP_KERNEL);
> +		if (!pll->new_config)
> +			return -ENOMEM;

Need to restore new_config = &config? For the crtc config we have
new_config==NULL outside modeset operations to catch abusers, but you
seem to have new_config==&config for the plls normally. I had the crtc
config that way too initially, but Daniel wanted to changed it. Not sure
how hard it would be to do the same thing for plls?

My original idea for the new_config==&config approach in crtcs was that
we might be able to share some functions that get called both during
and after modesets and they would automagically consult the correct
pipe config. But the NULL approach certainly seems to work so far and
it would result in a neat explosion if it didn't.

Also what happens with the already allocated pll configs if we fail
midway through the loop here? Or if we fail later in the
.compute_clock() or some other place before the pll config is commited?

Could also use kmemdup() here I suppose.

> +
> +		pll->new_config->crtc_mask =
> +			pll->config.crtc_mask & ~clear_pipes;
> +		pll->new_config->hw_state = pll->config.hw_state;
> +	}
> +
> +	return 0;
> +}
> +
> +static void intel_shared_dpll_commit(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_shared_dpll *pll;
> +	enum intel_dpll_id i;
> +
> +	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
> +		pll = &dev_priv->shared_dplls[i];
> +
> +		BUG_ON(pll->new_config == &pll->config);
> +
> +		pll->config = *pll->new_config;
> +		kfree(pll->new_config);
> +		pll->new_config = &pll->config;
> +	}
> +}
> +
>  static void cpt_verify_modeset(struct drm_device *dev, int pipe)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -5401,11 +5440,11 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
>  				     struct intel_crtc_config *pipe_config)
>  {
>  	struct drm_device *dev = crtc->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
>  
>  	/* FIXME should check pixel clock limits on all platforms */
>  	if (INTEL_INFO(dev)->gen < 4) {
> -		struct drm_i915_private *dev_priv = dev->dev_private;
>  		int clock_limit =
>  			dev_priv->display.get_display_clock_speed(dev);
>  
> @@ -5455,10 +5494,11 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
>  		hsw_compute_ips_config(crtc, pipe_config);
>  
>  	/*
> -	 * XXX: PCH/WRPLL clock sharing is done in ->mode_set, so make sure the
> -	 * old clock survives for now.
> +	 * XXX: PCH/WRPLL clock sharing is done in ->mode_set if ->compute_clock is not
> +	 * set, so make sure the old clock survives for now.
>  	 */
> -	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev) || HAS_DDI(dev))
> +	if (dev_priv->display.crtc_compute_clock == NULL &&
> +            (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev) || HAS_DDI(dev)))
>  		pipe_config->shared_dpll = crtc->config.shared_dpll;
>  
>  	if (pipe_config->has_pch_encoder)
> @@ -7328,6 +7368,9 @@ static int ironlake_crtc_mode_set(struct intel_crtc *crtc,
>  		else
>  			crtc->new_config->dpll_hw_state.fp1 = fp;
>  
> +		if (intel_crtc_to_shared_dpll(crtc))
> +			intel_put_shared_dpll(crtc);
> +
>  		pll = intel_get_shared_dpll(crtc);
>  		if (pll == NULL) {
>  			DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
> @@ -10986,6 +11029,20 @@ static int __intel_set_mode(struct drm_crtc *crtc,
>  		prepare_pipes &= ~disable_pipes;
>  	}
>  
> +	if (dev_priv->display.crtc_compute_clock) {
> +		unsigned clear_pipes = modeset_pipes | disable_pipes;
> +
> +		ret = intel_shared_dpll_start_config(dev_priv, clear_pipes);
> +		if (ret)
> +			goto done;
> +
> +		for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
> +			ret = dev_priv->display.crtc_compute_clock(intel_crtc);
> +			if (ret)
> +				goto done;
> +		}
> +	}
> +
>  	for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
>  		intel_crtc_disable(&intel_crtc->base);
>  
> @@ -11013,6 +11070,9 @@ static int __intel_set_mode(struct drm_crtc *crtc,
>  						&pipe_config->adjusted_mode);
>  	}
>  
> +	if (dev_priv->display.crtc_compute_clock)
> +		intel_shared_dpll_commit(dev_priv);
> +
>  	/* Only after disabling all output pipelines that will be changed can we
>  	 * update the the output configuration. */
>  	intel_modeset_update_state(dev, prepare_pipes);
> @@ -11047,9 +11107,12 @@ static int __intel_set_mode(struct drm_crtc *crtc,
>  		crtc->x = x;
>  		crtc->y = y;
>  
> -		ret = dev_priv->display.crtc_mode_set(intel_crtc, x, y, fb);
> -		if (ret)
> -			goto done;
> +		if (dev_priv->display.crtc_mode_set) {
> +			ret = dev_priv->display.crtc_mode_set(intel_crtc,
> +							      x, y, fb);
> +			if (ret)
> +				goto done;
> +		}
>  	}
>  
>  	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
> @@ -11599,6 +11662,8 @@ static void ibx_pch_dpll_init(struct drm_device *dev)
>  	dev_priv->num_shared_dpll = 2;
>  
>  	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
> +		dev_priv->shared_dplls[i].new_config =
> +			&dev_priv->shared_dplls[i].config;
>  		dev_priv->shared_dplls[i].id = i;
>  		dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
>  		dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set;
> @@ -12586,6 +12651,7 @@ static void intel_init_display(struct drm_device *dev)
>  	if (HAS_DDI(dev)) {
>  		dev_priv->display.get_pipe_config = haswell_get_pipe_config;
>  		dev_priv->display.get_plane_config = ironlake_get_plane_config;
> +		dev_priv->display.crtc_compute_clock = NULL;

dev_priv is kzalloc()ed so no need for NULL initialization.

>  		dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
>  		dev_priv->display.crtc_enable = haswell_crtc_enable;
>  		dev_priv->display.crtc_disable = haswell_crtc_disable;
> @@ -12599,6 +12665,7 @@ static void intel_init_display(struct drm_device *dev)
>  	} else if (HAS_PCH_SPLIT(dev)) {
>  		dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
>  		dev_priv->display.get_plane_config = ironlake_get_plane_config;
> +		dev_priv->display.crtc_compute_clock = NULL;
>  		dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
>  		dev_priv->display.crtc_enable = ironlake_crtc_enable;
>  		dev_priv->display.crtc_disable = ironlake_crtc_disable;
> @@ -12608,6 +12675,7 @@ static void intel_init_display(struct drm_device *dev)
>  	} else if (IS_VALLEYVIEW(dev)) {
>  		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
>  		dev_priv->display.get_plane_config = i9xx_get_plane_config;
> +		dev_priv->display.crtc_compute_clock = NULL;
>  		dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
>  		dev_priv->display.crtc_enable = valleyview_crtc_enable;
>  		dev_priv->display.crtc_disable = i9xx_crtc_disable;
> @@ -12617,6 +12685,7 @@ static void intel_init_display(struct drm_device *dev)
>  	} else {
>  		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
>  		dev_priv->display.get_plane_config = i9xx_get_plane_config;
> +		dev_priv->display.crtc_compute_clock = NULL;
>  		dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
>  		dev_priv->display.crtc_enable = i9xx_crtc_enable;
>  		dev_priv->display.crtc_disable = i9xx_crtc_disable;
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC

  reply	other threads:[~2014-10-22  8:33 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-21 13:02 [PATCH 0/8] Stage shared dpll config Ander Conselvan de Oliveira
2014-10-21 13:02 ` [PATCH 1/8] drm/i915: Convert shared dpll reference count to a crtc mask Ander Conselvan de Oliveira
2014-10-22  8:13   ` Ville Syrjälä
2014-10-21 13:02 ` [PATCH 2/8] drm/i915: Move dpll crtc_mask and hw_state fields into separate struct Ander Conselvan de Oliveira
2014-10-28 16:44   ` Damien Lespiau
2014-10-21 13:02 ` [PATCH 3/8] drm/i915: Add infrastructure for choosing DPLLs before disabling crtcs Ander Conselvan de Oliveira
2014-10-22  8:33   ` Ville Syrjälä [this message]
2014-10-22 11:33     ` Ander Conselvan de Oliveira
2014-10-21 13:02 ` [PATCH 4/8] drm/i915: Covert HSW+ to choose DPLLS before disabling CRTCs Ander Conselvan de Oliveira
2014-10-21 13:02 ` [PATCH 5/8] drm/i915: Covert ILK-IVB " Ander Conselvan de Oliveira
2014-10-21 13:02 ` [PATCH 6/8] drm/i915: Covert remaining platforms " Ander Conselvan de Oliveira
2014-10-21 13:02 ` [PATCH 7/8] drm/i915: Remove crtc_mode_set() hook Ander Conselvan de Oliveira
2014-10-21 13:02 ` [PATCH 8/8] drm/i915: Don't store current shared DPLL in the new pipe_config Ander Conselvan de Oliveira

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20141022083321.GV4284@intel.com \
    --to=ville.syrjala@linux.intel.com \
    --cc=ander.conselvan.de.oliveira@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=shuang.he@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox