Re: [PATCH 1/5] drm/i915: add and enable DP AUX CH mutex

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 13 Feb 2018, José Roberto de Souza <jose.souza@xxxxxxxxx> wrote:
> When PSR/PSR2 is enabled hardware can do AUX transactions by it self, so
> lets use the mutex register that is available in gen9+ to avoid concurrent
> access by hardware and driver.
>
> Reference: https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-skl-vol12-display.pdf
> Page 198 - AUX programming sequence
>
> As gen < 9 don't have the mutex PSR needs to be disabled, that is why the
> 'else TODO' was added. This is also backed by spec:
> "DDI A AUX channel transactions must not be sent while SRD is enabled.
> SRD must be completely disabled before a DDI A AUX channel transaction can
> be sent." BSpec: 7530

We explicitly rejected the use of the hw mutex way back when Skylake was
enabled. At that time the understanding was that the hw will try to do
the arbitration itself. Has something changed?

Some comments inline.

>
> Cc: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx>
> Signed-off-by: José Roberto de Souza <jose.souza@xxxxxxxxx>
> ---
>  drivers/gpu/drm/i915/i915_reg.h  |  9 ++++++++
>  drivers/gpu/drm/i915/intel_dp.c  | 48 ++++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_drv.h |  1 +
>  drivers/gpu/drm/i915/intel_psr.c |  6 +++++
>  4 files changed, 64 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index f6afa5e5e7c1..5d7736117cb9 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -5318,6 +5318,7 @@ enum {
>  #define _DPA_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6401c)
>  #define _DPA_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64020)
>  #define _DPA_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64024)
> +#define _DPA_AUX_CH_MUTEX	(dev_priv->info.display_mmio_offset + 0x6402C)
>  
>  #define _DPB_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64110)
>  #define _DPB_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64114)
> @@ -5325,6 +5326,7 @@ enum {
>  #define _DPB_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6411c)
>  #define _DPB_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64120)
>  #define _DPB_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64124)
> +#define _DPB_AUX_CH_MUTEX	(dev_priv->info.display_mmio_offset + 0x6412C)
>  
>  #define _DPC_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64210)
>  #define _DPC_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64214)
> @@ -5332,6 +5334,7 @@ enum {
>  #define _DPC_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6421c)
>  #define _DPC_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64220)
>  #define _DPC_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64224)
> +#define _DPC_AUX_CH_MUTEX	(dev_priv->info.display_mmio_offset + 0x6422C)
>  
>  #define _DPD_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64310)
>  #define _DPD_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64314)
> @@ -5339,6 +5342,7 @@ enum {
>  #define _DPD_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6431c)
>  #define _DPD_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64320)
>  #define _DPD_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64324)
> +#define _DPD_AUX_CH_MUTEX	(dev_priv->info.display_mmio_offset + 0x6432C)
>  
>  #define _DPF_AUX_CH_CTL		(dev_priv->info.display_mmio_offset + 0x64510)
>  #define _DPF_AUX_CH_DATA1	(dev_priv->info.display_mmio_offset + 0x64514)
> @@ -5346,9 +5350,11 @@ enum {
>  #define _DPF_AUX_CH_DATA3	(dev_priv->info.display_mmio_offset + 0x6451c)
>  #define _DPF_AUX_CH_DATA4	(dev_priv->info.display_mmio_offset + 0x64520)
>  #define _DPF_AUX_CH_DATA5	(dev_priv->info.display_mmio_offset + 0x64524)
> +#define _DPF_AUX_CH_MUTEX	(dev_priv->info.display_mmio_offset + 0x6452C)
>  
>  #define DP_AUX_CH_CTL(port)	_MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)
>  #define DP_AUX_CH_DATA(port, i)	_MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */
> +#define DP_AUX_CH_MUTEX(port)	_MMIO_PORT(port, _DPA_AUX_CH_MUTEX, _DPB_AUX_CH_MUTEX)
>  
>  #define   DP_AUX_CH_CTL_SEND_BUSY	    (1 << 31)
>  #define   DP_AUX_CH_CTL_DONE		    (1 << 30)
> @@ -5378,6 +5384,9 @@ enum {
>  #define   DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(c) (((c) - 1) << 5)
>  #define   DP_AUX_CH_CTL_SYNC_PULSE_SKL(c)   ((c) - 1)
>  
> +#define   DP_AUX_CH_MUTEX_ENABLE		(1 << 31)
> +#define   DP_AUX_CH_MUTEX_STATUS		(1 << 30)

The bit definitions should immediately follow the register offset
definition. I.e. DP_AUX_CH_MUTEX() should be right above these.

> +
>  /*
>   * Computing GMCH M and N values for the Display Port link
>   *
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index f20b25f98e5a..bd5f1bb730ff 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1081,6 +1081,28 @@ static uint32_t intel_dp_get_aux_send_ctl(struct intel_dp *intel_dp,
>  						aux_clock_divider);
>  }
>  
> +static bool intel_dp_aux_get(struct drm_i915_private *dev_priv,
> +			     struct intel_dp *intel_dp)

You can get at dev_priv from intel_dp, please don't pass both.

The names _get/_put imply the calls can be nested, which is not the case
here. Please use _lock/_unlock instead.

If the locking can fail, call it _trylock.

> +{
> +	int try, ret;
> +
> +	for (try = 0, ret = -1; try < 3 && ret; try++)
> +		ret = wait_for(!(I915_READ_NOTRACE(intel_dp->aux_ch_mutex_reg)
> +				 & DP_AUX_CH_MUTEX_STATUS), 0.5);

0.5? Really?

What's the point of the loop around the wait_for? wait_for already loops
with increasing delays in between the condition check.

> +
> +	return ret == 0;
> +}
> +
> +static void intel_dp_aux_put(struct drm_i915_private *dev_priv,
> +			     struct intel_dp *intel_dp)
> +{
> +	/* setting the status bit releases the mutex + keep set the bit
> +	 * to keep the mutex enabled.
> +	 */
> +	I915_WRITE(intel_dp->aux_ch_mutex_reg, DP_AUX_CH_MUTEX_ENABLE |
> +		   DP_AUX_CH_MUTEX_STATUS);
> +}
> +
>  static int
>  intel_dp_aux_ch(struct intel_dp *intel_dp,
>  		const uint8_t *send, int send_bytes,
> @@ -1115,6 +1137,21 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
>  
>  	intel_dp_check_edp(intel_dp);
>  
> +	/* Get hardware mutex when PSR is enabled */
> +	if (dev_priv->psr.enabled == intel_dp) {
> +		if (intel_dp->aux_ch_mutex_reg.reg) {

See i915_mmio_reg_valid(). But I'd rather the check was within the
locking primitives.

Overall I think mixing all this PSR conditional stuff in the aux channel
primitives is very, very wrong.

At the very least this is racy with PSR enabling/disabling.

> +			if (intel_dp_aux_get(dev_priv, intel_dp)) {
> +				DRM_WARN("dp_aux_ch port locked for too long");
> +				ret = -EBUSY;
> +				goto out_locked;
> +			}
> +		} else {
> +			/* TODO: go to PSR exit state waiting for change before
> +			 * do a aux ch transaction.
> +			 */
> +		}
> +	}
> +
>  	/* Try to wait for any previous AUX channel activity */
>  	for (try = 0; try < 3; try++) {
>  		status = I915_READ_NOTRACE(ch_ctl);
> @@ -1243,7 +1280,16 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
>  				    recv + i, recv_bytes - i);
>  
>  	ret = recv_bytes;
> +
>  out:
> +	if (dev_priv->psr.enabled == intel_dp) {
> +		if (intel_dp->aux_ch_mutex_reg.reg)
> +			intel_dp_aux_put(dev_priv, intel_dp);
> +		else
> +			/* TODO: schedule PSR work to active PSR again */
> +	}
> +
> +out_locked:
>  	pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
>  
>  	if (vdd)
> @@ -1496,6 +1542,8 @@ static void intel_aux_reg_init(struct intel_dp *intel_dp)
>  	intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port);
>  	for (i = 0; i < ARRAY_SIZE(intel_dp->aux_ch_data_reg); i++)
>  		intel_dp->aux_ch_data_reg[i] = intel_aux_data_reg(dev_priv, port, i);
> +	if (INTEL_INFO(dev_priv)->gen >= 9)
> +		intel_dp->aux_ch_mutex_reg = DP_AUX_CH_MUTEX(port);
>  }
>  
>  static void
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 898064e8bea7..0d235b7dab21 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1040,6 +1040,7 @@ struct intel_dp {
>  	i915_reg_t output_reg;
>  	i915_reg_t aux_ch_ctl_reg;
>  	i915_reg_t aux_ch_data_reg[5];
> +	i915_reg_t aux_ch_mutex_reg;
>  	uint32_t DP;
>  	int link_rate;
>  	uint8_t lane_count;
> diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
> index 2ef374f936b9..8b456e4e1b47 100644
> --- a/drivers/gpu/drm/i915/intel_psr.c
> +++ b/drivers/gpu/drm/i915/intel_psr.c
> @@ -484,6 +484,9 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp,
>  			   EDP_PSR_DEBUG_MASK_HPD |
>  			   EDP_PSR_DEBUG_MASK_LPSP);
>  	}
> +
> +	if (intel_dp->aux_ch_mutex_reg.reg)
> +		I915_WRITE(intel_dp->aux_ch_mutex_reg, DP_AUX_CH_MUTEX_ENABLE);

You can't just go stomping on the register without locking. Racy.

>  }
>  
>  /**
> @@ -617,6 +620,9 @@ static void hsw_psr_disable(struct intel_dp *intel_dp,
>  		else
>  			WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
>  	}
> +
> +	if (intel_dp->aux_ch_mutex_reg.reg)
> +		I915_WRITE(intel_dp->aux_ch_mutex_reg, ~DP_AUX_CH_MUTEX_ENABLE);

Are you sure you want to set all other bits than enable?


BR,
Jani.

>  }
>  
>  /**

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux