diff mbox

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

Message ID 20180214002917.31252-1-jose.souza@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Souza, Jose Feb. 14, 2018, 12:29 a.m. UTC
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

Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 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(+)

Comments

Rodrigo Vivi Feb. 14, 2018, 1:30 a.m. UTC | #1
José Roberto de Souza <jose.souza@intel.com> writes:

> 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
>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>  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)
> +
>  /*
>   * 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)
> +{
> +	int try, ret;

Here you are not getting the aux. You are only getting checking if aux
is available.
My understanding of the spec is that the actual get is set Enable bit.

> +
> +	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);

what about
intel_wait_for_register(dev_priv, intel_dp->aux_ch_mutex_reg,
				    DP_AUX_CH_MUTEX_STATUS, 0,
				    500)
?

> +
> +	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 |

The enable bit is optional here.
I believe it gets cleaner without it but with RMW.

> +		   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) {

these checks could be inside get function.

> +			if (intel_dp_aux_get(dev_priv, intel_dp)) {
> +				DRM_WARN("dp_aux_ch port locked for too
> long");

as well the message DRM_ERROR is enough I thing.

> +				ret = -EBUSY;
also specific errno

> +				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) {

we are checking psr.enable out of psr mutexes...
probably better to only do this once on get part
and if you got you put...

> +		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);

My understanding is that set Enable is the actual get hw mutex,
so I don't believe you want do do this here.

Also you already check for psr.enable inside the aux transaction.
setting there should be enough.

>  }
>  
>  /**
> @@ -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);
>  }
>  
>  /**
> -- 
> 2.16.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Souza, Jose Feb. 14, 2018, 2:30 a.m. UTC | #2
On Tue, 2018-02-13 at 17:30 -0800, Rodrigo Vivi wrote:
> José Roberto de Souza <jose.souza@intel.com> writes:

> 

> > 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-g

> > fx-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

> > 

> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>

> > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>

> > ---

> >  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)

> > +

> >  /*

> >   * 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)

> > +{

> > +	int try, ret;

> 

> Here you are not getting the aux. You are only getting checking if

> aux

> is available.

> My understanding of the spec is that the actual get is set Enable

> bit.


The spec is not clear but because of this 2 statements I think this is
correct:

- statement 1:
Release with (is optional) or without disabling MUTEX function.
DDI_AUX_MUTEX[31:30]= "11"
OR
DDI_AUX_MUTEX[31:30]="01"

So here you release the mutex by always seting the bit 30(status) and
is optinal disable the mutex.

- statement 2:
Enable MUTEX without changing MUTEX status
DDI_AUX_MUTEX[31]='1'

Also adding a few aux transactions before and after PSR exit/enable I
was able to confirm that the hardware got the mutex as the status bit
was set and after sleep for 500usec it was released.

> 

> > +

> > +	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);

> 

> what about

> intel_wait_for_register(dev_priv, intel_dp->aux_ch_mutex_reg,

> 				    DP_AUX_CH_MUTEX_STATUS, 0,

> 				    500)

> ?


This difference that I can see between wait_for() and
intel_wait_for_register() is that intel_wait_for_register() will call
intel_uncore_forcewake_get__locked()/put_locked() is used to kept the
hardware domain wake?
I'm fine with both but intel_wait_for_register() have a msec parameter
so the timeout would need to be 2msec or 3mesc(something between the
actual 1.5msec).

> 

> > +

> > +	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 |

> 

> The enable bit is optional here.

> I believe it gets cleaner without it but with RMW.


See why I belive this is correct above.

> 

> > +		   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) {

> 

> these checks could be inside get function.


Huum and in case of gen < 9, exit PSR inside of this function?

> 

> > +			if (intel_dp_aux_get(dev_priv, intel_dp))

> > {

> > +				DRM_WARN("dp_aux_ch port locked

> > for too

> > long");

> 

> as well the message DRM_ERROR is enough I thing.


ack

> 

> > +				ret = -EBUSY;

> 

> also specific errno


ack

> 

> > +				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) {

> 

> we are checking psr.enable out of psr mutexes...

> probably better to only do this once on get part

> and if you got you put...


ack

> 

> > +		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);

> 

> My understanding is that set Enable is the actual get hw mutex,

> so I don't believe you want do do this here.

> 

> Also you already check for psr.enable inside the aux transaction.

> setting there should be enough.


See above.

> 

> >  }

> >  

> >  /**

> > @@ -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);

> >  }

> >  

> >  /**

> > -- 

> > 2.16.1

> > 

> > _______________________________________________

> > Intel-gfx mailing list

> > Intel-gfx@lists.freedesktop.org

> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Jani Nikula Feb. 14, 2018, 7:32 a.m. UTC | #3
On Tue, 13 Feb 2018, José Roberto de Souza <jose.souza@intel.com> 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:

And proves the patches weren't compiled not to mention tested. :(

BR,
Jani.



> "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
>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>  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)
> +
>  /*
>   * 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)
> +{
> +	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);
> +
> +	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) {
> +			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);
>  }
>  
>  /**
> @@ -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);
>  }
>  
>  /**
Jani Nikula Feb. 14, 2018, 9:47 a.m. UTC | #4
On Tue, 13 Feb 2018, José Roberto de Souza <jose.souza@intel.com> 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@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>  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.

>  }
>  
>  /**
Ville Syrjala Feb. 14, 2018, 1:43 p.m. UTC | #5
On Tue, Feb 13, 2018 at 05:30:29PM -0800, Rodrigo Vivi wrote:
> José Roberto de Souza <jose.souza@intel.com> writes:
> 
> > 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
> >
> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> > ---
> >  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)
> > +
> >  /*
> >   * 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)
> > +{
> > +	int try, ret;
> 
> Here you are not getting the aux. You are only getting checking if aux
> is available.
> My understanding of the spec is that the actual get is set Enable bit.
> 
> > +
> > +	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);
> 
> what about
> intel_wait_for_register(dev_priv, intel_dp->aux_ch_mutex_reg,
> 				    DP_AUX_CH_MUTEX_STATUS, 0,
> 				    500)

IIRC when I asked Art about the mutex he indicated that the hardware has
no magic fair arbitration mechanism. So I think what we want to do is
first check if the mutex is free, if not we could try to wait for the
expected 500us (or poll somewhat infrequently), but if after a while
the mutex still isn't free we should probably start hammering it hard
so that have a better chance of actually getting it.

> ?
> 
> > +
> > +	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 |
> 
> The enable bit is optional here.
> I believe it gets cleaner without it but with RMW.
> 
> > +		   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) {
> 
> these checks could be inside get function.
> 
> > +			if (intel_dp_aux_get(dev_priv, intel_dp)) {
> > +				DRM_WARN("dp_aux_ch port locked for too
> > long");
> 
> as well the message DRM_ERROR is enough I thing.
> 
> > +				ret = -EBUSY;
> also specific errno
> 
> > +				goto out_locked;
> > +			}
> > +		} else {
> > +			/* TODO: go to PSR exit state waiting for change before
> > +			 * do a aux ch transaction.
> > +			 */
> > +		}
> > +	}

This looks needlessly complicated. IMO it should just be something like:

if (!skl_aux_hw_mutex_get())
	goto fail;

And I'm thinking we should just ignore the PSR on vs. off case,
and just do this for eDP always. I can't recall if GTC is a thing
for normak DP, but if it is and we ever enable it then we'd obviously
need to start doing this for all DP port.

> > +
> >  	/* 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) {
> 
> we are checking psr.enable out of psr mutexes...
> probably better to only do this once on get part
> and if you got you put...
> 
> > +		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);

No point in adding this thing IMO.

> >  }
> >  
> >  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);
> 
> My understanding is that set Enable is the actual get hw mutex,
> so I don't believe you want do do this here.

The register read is the 'get'. But I also think we should just set the
enable bit in the _get() function as well. I don't think there should be
any harm if we just leave the enable bit set permenently after that.

> 
> Also you already check for psr.enable inside the aux transaction.
> setting there should be enough.
> 
> >  }
> >  
> >  /**
> > @@ -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);
> >  }
> >  
> >  /**
> > -- 
> > 2.16.1
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Rodrigo Vivi Feb. 14, 2018, 4:21 p.m. UTC | #6
On Wed, Feb 14, 2018 at 09:47:00AM +0000, Jani Nikula wrote:
> On Tue, 13 Feb 2018, José Roberto de Souza <jose.souza@intel.com> 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?

By that time spec wasn't clear about the actual need or its reliability.
Nowdays spec is clear that that is absolutely needed for PSR/PSR2/GTC.

Also we were using a lot of SW tracking and nowadays we are moving PSR
to use more HW tracking.

So I believe we should add this to get a stable PSR.

> 
> Some comments inline.
> 
> >
> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> > ---
> >  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
Jani Nikula Feb. 14, 2018, 4:37 p.m. UTC | #7
On Wed, 14 Feb 2018, Rodrigo Vivi <rodrigo.vivi@intel.com> wrote:
> On Wed, Feb 14, 2018 at 09:47:00AM +0000, Jani Nikula wrote:
>> On Tue, 13 Feb 2018, José Roberto de Souza <jose.souza@intel.com> 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?
>
> By that time spec wasn't clear about the actual need or its reliability.
> Nowdays spec is clear that that is absolutely needed for PSR/PSR2/GTC.
>
> Also we were using a lot of SW tracking and nowadays we are moving PSR
> to use more HW tracking.
>
> So I believe we should add this to get a stable PSR.

Fair enough. The patch at hand needs a bunch of work though.

BR,
Jani.


>
>> 
>> Some comments inline.
>> 
>> >
>> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>> > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
>> > ---
>> >  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
diff mbox

Patch

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)
+
 /*
  * 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)
+{
+	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);
+
+	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) {
+			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);
 }
 
 /**
@@ -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);
 }
 
 /**