diff mbox series

[PATCHv4] drm/i915/display/dp: On AUX xfer timeout restart freshly

Message ID 20230619082715.922094-1-arun.r.murthy@intel.com (mailing list archive)
State New, archived
Headers show
Series [PATCHv4] drm/i915/display/dp: On AUX xfer timeout restart freshly | expand

Commit Message

Murthy, Arun R June 19, 2023, 8:27 a.m. UTC
At the beginning of the aux transfer a check for aux control busy bit is
done. Then as per the spec on aux transfer timeout, need to retry
freshly for 3 times with a delay which is taken care by the control
register.
On each of these 3 trials a check for busy has to be done so as to start
freshly.

v2: updated the commit message
v4: check for SEND_BUSY after write (Imre)

Signed-off-by: Arun R Murthy <arun.r.murthy@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_aux.c | 58 +++++++++------------
 1 file changed, 26 insertions(+), 32 deletions(-)

Comments

kernel test robot June 19, 2023, 11:08 a.m. UTC | #1
Hi Arun,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-tip/drm-tip]

url:    https://github.com/intel-lab-lkp/linux/commits/Arun-R-Murthy/drm-i915-display-dp-On-AUX-xfer-timeout-restart-freshly/20230619-163622
base:   git://anongit.freedesktop.org/drm/drm-tip drm-tip
patch link:    https://lore.kernel.org/r/20230619082715.922094-1-arun.r.murthy%40intel.com
patch subject: [Intel-gfx] [PATCHv4] drm/i915/display/dp: On AUX xfer timeout restart freshly
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20230619/202306191845.yMTzbDgG-lkp@intel.com/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce: (https://download.01.org/0day-ci/archive/20230619/202306191845.yMTzbDgG-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306191845.yMTzbDgG-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/i915/display/intel_dp_aux.c:284:12: warning: variable 'aux_clock_divider' is uninitialized when used here [-Wuninitialized]
                                                 aux_clock_divider);
                                                 ^~~~~~~~~~~~~~~~~
   drivers/gpu/drm/i915/display/intel_dp_aux.c:222:23: note: initialize the variable 'aux_clock_divider' to silence this warning
           u32 aux_clock_divider;
                                ^
                                 = 0
   1 warning generated.


vim +/aux_clock_divider +284 drivers/gpu/drm/i915/display/intel_dp_aux.c

   209	
   210	static int
   211	intel_dp_aux_xfer(struct intel_dp *intel_dp,
   212			  const u8 *send, int send_bytes,
   213			  u8 *recv, int recv_size,
   214			  u32 aux_send_ctl_flags)
   215	{
   216		struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
   217		struct drm_i915_private *i915 =
   218				to_i915(dig_port->base.base.dev);
   219		enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
   220		bool is_tc_port = intel_phy_is_tc(i915, phy);
   221		i915_reg_t ch_ctl, ch_data[5];
   222		u32 aux_clock_divider;
   223		enum intel_display_power_domain aux_domain;
   224		intel_wakeref_t aux_wakeref;
   225		intel_wakeref_t pps_wakeref;
   226		int i, ret, recv_bytes;
   227		int try, clock = 0;
   228		u32 status;
   229		u32 send_ctl;
   230		bool vdd;
   231	
   232		ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
   233		for (i = 0; i < ARRAY_SIZE(ch_data); i++)
   234			ch_data[i] = intel_dp->aux_ch_data_reg(intel_dp, i);
   235	
   236		if (is_tc_port) {
   237			intel_tc_port_lock(dig_port);
   238			/*
   239			 * Abort transfers on a disconnected port as required by
   240			 * DP 1.4a link CTS 4.2.1.5, also avoiding the long AUX
   241			 * timeouts that would otherwise happen.
   242			 * TODO: abort the transfer on non-TC ports as well.
   243			 */
   244			if (!intel_tc_port_connected_locked(&dig_port->base)) {
   245				ret = -ENXIO;
   246				goto out_unlock;
   247			}
   248		}
   249	
   250		aux_domain = intel_aux_power_domain(dig_port);
   251	
   252		aux_wakeref = intel_display_power_get(i915, aux_domain);
   253		pps_wakeref = intel_pps_lock(intel_dp);
   254	
   255		/*
   256		 * We will be called with VDD already enabled for dpcd/edid/oui reads.
   257		 * In such cases we want to leave VDD enabled and it's up to upper layers
   258		 * to turn it off. But for eg. i2c-dev access we need to turn it on/off
   259		 * ourselves.
   260		 */
   261		vdd = intel_pps_vdd_on_unlocked(intel_dp);
   262	
   263		/*
   264		 * dp aux is extremely sensitive to irq latency, hence request the
   265		 * lowest possible wakeup latency and so prevent the cpu from going into
   266		 * deep sleep states.
   267		 */
   268		cpu_latency_qos_update_request(&intel_dp->pm_qos, 0);
   269	
   270		intel_pps_check_power_unlocked(intel_dp);
   271	
   272		/*
   273		 * FIXME PSR should be disabled here to prevent
   274		 * it using the same AUX CH simultaneously
   275		 */
   276	
   277		/* Only 5 data registers! */
   278		if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
   279			ret = -E2BIG;
   280			goto out;
   281		}
   282		send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
   283						      send_bytes,
 > 284						      aux_clock_divider);
   285		send_ctl |= aux_send_ctl_flags;
   286	
   287		while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
   288			/* Re-visit : Must try at least 3 times according to DP spec */
   289			for (try = 0; try < 5; try++) {
   290				/* Try to wait for any previous AUX channel activity */
   291				status = intel_dp_aux_wait_done(intel_dp);
   292				/* just trace the final value */
   293				trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
   294	
   295				if (status & DP_AUX_CH_CTL_SEND_BUSY) {
   296					drm_WARN(&i915->drm, 1,
   297						 "%s: not started, previous Tx still in process (status 0x%08x)\n",
   298						 intel_dp->aux.name, status);
   299					intel_dp->aux_busy_last_status = status;
   300					if (try > 3) {
   301						ret = -EBUSY;
   302						goto out;
   303					} else
   304						continue;
   305				}
   306	
   307				/* Load the send data into the aux channel data registers */
   308				for (i = 0; i < send_bytes; i += 4)
   309					intel_de_write(i915, ch_data[i >> 2],
   310						       intel_dp_aux_pack(send + i,
   311									 send_bytes - i));
   312	
   313				/* Send the command and wait for it to complete */
   314				intel_de_write(i915, ch_ctl, send_ctl);
   315	
   316				/* TODO: if typeC then 4.2ms else 800us. For DG2 add 1.5ms for both cases */
   317				status = intel_dp_aux_wait_done(intel_dp);
   318	
   319				/* Clear done status and any errors */
   320				intel_de_write(i915, ch_ctl,
   321					       status | DP_AUX_CH_CTL_DONE |
   322					       DP_AUX_CH_CTL_TIME_OUT_ERROR |
   323					       DP_AUX_CH_CTL_RECEIVE_ERROR);
   324	
   325				/*
   326				 * DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
   327				 *   400us delay required for errors and timeouts
   328				 *   Timeout errors from the HW already meet this
   329				 *   requirement so skip to next iteration
   330				 */
   331				if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
   332							DP_AUX_CH_CTL_SEND_BUSY))
   333					continue;
   334	
   335				if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
   336					usleep_range(400, 500);
   337					continue;
   338				}
   339				if (status & DP_AUX_CH_CTL_DONE)
   340					goto done;
   341			}
   342		}
   343	
   344		if ((status & DP_AUX_CH_CTL_DONE) == 0) {
   345			drm_err(&i915->drm, "%s: not done (status 0x%08x)\n",
   346				intel_dp->aux.name, status);
   347			ret = -EBUSY;
   348			goto out;
   349		}
   350	
   351	done:
   352		/*
   353		 * Check for timeout or receive error. Timeouts occur when the sink is
   354		 * not connected.
   355		 */
   356		if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
   357			drm_err(&i915->drm, "%s: receive error (status 0x%08x)\n",
   358				intel_dp->aux.name, status);
   359			ret = -EIO;
   360			goto out;
   361		}
   362	
   363		/*
   364		 * Timeouts occur when the device isn't connected, so they're "normal"
   365		 * -- don't fill the kernel log with these
   366		 */
   367		if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
   368			drm_dbg_kms(&i915->drm, "%s: timeout (status 0x%08x)\n",
   369				    intel_dp->aux.name, status);
   370			ret = -ETIMEDOUT;
   371			goto out;
   372		}
   373	
   374		/* Unload any bytes sent back from the other side */
   375		recv_bytes = REG_FIELD_GET(DP_AUX_CH_CTL_MESSAGE_SIZE_MASK, status);
   376	
   377		/*
   378		 * By BSpec: "Message sizes of 0 or >20 are not allowed."
   379		 * We have no idea of what happened so we return -EBUSY so
   380		 * drm layer takes care for the necessary retries.
   381		 */
   382		if (recv_bytes == 0 || recv_bytes > 20) {
   383			drm_dbg_kms(&i915->drm,
   384				    "%s: Forbidden recv_bytes = %d on aux transaction\n",
   385				    intel_dp->aux.name, recv_bytes);
   386			ret = -EBUSY;
   387			goto out;
   388		}
   389	
   390		if (recv_bytes > recv_size)
   391			recv_bytes = recv_size;
   392	
   393		for (i = 0; i < recv_bytes; i += 4)
   394			intel_dp_aux_unpack(intel_de_read(i915, ch_data[i >> 2]),
   395					    recv + i, recv_bytes - i);
   396	
   397		ret = recv_bytes;
   398	out:
   399		cpu_latency_qos_update_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE);
   400	
   401		if (vdd)
   402			intel_pps_vdd_off_unlocked(intel_dp, false);
   403	
   404		intel_pps_unlock(intel_dp, pps_wakeref);
   405		intel_display_power_put_async(i915, aux_domain, aux_wakeref);
   406	out_unlock:
   407		if (is_tc_port)
   408			intel_tc_port_unlock(dig_port);
   409	
   410		return ret;
   411	}
   412
Jani Nikula June 19, 2023, 12:07 p.m. UTC | #2
On Mon, 19 Jun 2023, Arun R Murthy <arun.r.murthy@intel.com> wrote:
> At the beginning of the aux transfer a check for aux control busy bit is
> done. Then as per the spec on aux transfer timeout, need to retry
> freshly for 3 times with a delay which is taken care by the control
> register.
> On each of these 3 trials a check for busy has to be done so as to start
> freshly.
>
> v2: updated the commit message
> v4: check for SEND_BUSY after write (Imre)
>
> Signed-off-by: Arun R Murthy <arun.r.murthy@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_dp_aux.c | 58 +++++++++------------
>  1 file changed, 26 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> index 21b50a5c8a85..abe8047fac39 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> @@ -226,6 +226,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
>  	int i, ret, recv_bytes;
>  	int try, clock = 0;
>  	u32 status;
> +	u32 send_ctl;
>  	bool vdd;
>  
>  	ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
> @@ -273,45 +274,36 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
>  	 * it using the same AUX CH simultaneously
>  	 */
>  
> -	/* Try to wait for any previous AUX channel activity */
> -	for (try = 0; try < 3; try++) {
> -		status = intel_de_read_notrace(i915, ch_ctl);
> -		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
> -			break;
> -		msleep(1);
> -	}
> -	/* just trace the final value */
> -	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> -
> -	if (try == 3) {
> -		const u32 status = intel_de_read(i915, ch_ctl);
> -
> -		if (status != intel_dp->aux_busy_last_status) {
> -			drm_WARN(&i915->drm, 1,
> -				 "%s: not started (status 0x%08x)\n",
> -				 intel_dp->aux.name, status);
> -			intel_dp->aux_busy_last_status = status;
> -		}
> -
> -		ret = -EBUSY;
> -		goto out;
> -	}
> -
>  	/* Only 5 data registers! */
>  	if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
>  		ret = -E2BIG;
>  		goto out;
>  	}
> +	send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
> +					      send_bytes,
> +					      aux_clock_divider);
> +	send_ctl |= aux_send_ctl_flags;
>  
>  	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
> -		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
> -							  send_bytes,
> -							  aux_clock_divider);
> -
> -		send_ctl |= aux_send_ctl_flags;

You can't move the send_ctl assignment outside the loop, because the
loop changes aux_clock_divider which affects send_ctl.

Please take your time with the next version, and don't try to rush it,
and we'll get this done quicker.

> -
> -		/* Must try at least 3 times according to DP spec */
> +		/* Re-visit : Must try at least 3 times according to DP spec */

How is this change helpful?

>  		for (try = 0; try < 5; try++) {
> +			/* Try to wait for any previous AUX channel activity */
> +			status = intel_dp_aux_wait_done(intel_dp);
> +			/* just trace the final value */
> +			trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> +
> +			if (status & DP_AUX_CH_CTL_SEND_BUSY) {
> +				drm_WARN(&i915->drm, 1,
> +					 "%s: not started, previous Tx still in process (status 0x%08x)\n",
> +					 intel_dp->aux.name, status);
> +				intel_dp->aux_busy_last_status = status;
> +				if (try > 3) {
> +					ret = -EBUSY;
> +					goto out;
> +				} else
> +					continue;

If one branch needs braces, all of them do.

> +			}
> +
>  			/* Load the send data into the aux channel data registers */
>  			for (i = 0; i < send_bytes; i += 4)
>  				intel_de_write(i915, ch_data[i >> 2],
> @@ -321,6 +313,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
>  			/* Send the command and wait for it to complete */
>  			intel_de_write(i915, ch_ctl, send_ctl);
>  
> +			/* TODO: if typeC then 4.2ms else 800us. For DG2 add 1.5ms for both cases */
>  			status = intel_dp_aux_wait_done(intel_dp);
>  
>  			/* Clear done status and any errors */
> @@ -335,7 +328,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
>  			 *   Timeout errors from the HW already meet this
>  			 *   requirement so skip to next iteration
>  			 */
> -			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
> +			if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
> +						DP_AUX_CH_CTL_SEND_BUSY))

The indentation is off.

>  				continue;
>  
>  			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
Murthy, Arun R June 19, 2023, 4 p.m. UTC | #3
> -----Original Message-----
> From: Nikula, Jani <jani.nikula@intel.com>
> Sent: Monday, June 19, 2023 5:37 PM
> To: Murthy, Arun R <arun.r.murthy@intel.com>; intel-
> gfx@lists.freedesktop.org
> Cc: Deak, Imre <imre.deak@intel.com>; Kahola, Mika
> <mika.kahola@intel.com>; Murthy, Arun R <arun.r.murthy@intel.com>
> Subject: Re: [PATCHv4] drm/i915/display/dp: On AUX xfer timeout restart
> freshly
> 
> On Mon, 19 Jun 2023, Arun R Murthy <arun.r.murthy@intel.com> wrote:
> > At the beginning of the aux transfer a check for aux control busy bit
> > is done. Then as per the spec on aux transfer timeout, need to retry
> > freshly for 3 times with a delay which is taken care by the control
> > register.
> > On each of these 3 trials a check for busy has to be done so as to
> > start freshly.
> >
> > v2: updated the commit message
> > v4: check for SEND_BUSY after write (Imre)
> >
> > Signed-off-by: Arun R Murthy <arun.r.murthy@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_dp_aux.c | 58
> > +++++++++------------
> >  1 file changed, 26 insertions(+), 32 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c
> > b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> > index 21b50a5c8a85..abe8047fac39 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
> > @@ -226,6 +226,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
> >  	int i, ret, recv_bytes;
> >  	int try, clock = 0;
> >  	u32 status;
> > +	u32 send_ctl;
> >  	bool vdd;
> >
> >  	ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
> > @@ -273,45 +274,36 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
> >  	 * it using the same AUX CH simultaneously
> >  	 */
> >
> > -	/* Try to wait for any previous AUX channel activity */
> > -	for (try = 0; try < 3; try++) {
> > -		status = intel_de_read_notrace(i915, ch_ctl);
> > -		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
> > -			break;
> > -		msleep(1);
> > -	}
> > -	/* just trace the final value */
> > -	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
> > -
> > -	if (try == 3) {
> > -		const u32 status = intel_de_read(i915, ch_ctl);
> > -
> > -		if (status != intel_dp->aux_busy_last_status) {
> > -			drm_WARN(&i915->drm, 1,
> > -				 "%s: not started (status 0x%08x)\n",
> > -				 intel_dp->aux.name, status);
> > -			intel_dp->aux_busy_last_status = status;
> > -		}
> > -
> > -		ret = -EBUSY;
> > -		goto out;
> > -	}
> > -
> >  	/* Only 5 data registers! */
> >  	if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
> >  		ret = -E2BIG;
> >  		goto out;
> >  	}
> > +	send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
> > +					      send_bytes,
> > +					      aux_clock_divider);
> > +	send_ctl |= aux_send_ctl_flags;
> >
> >  	while ((aux_clock_divider = intel_dp-
> >get_aux_clock_divider(intel_dp, clock++))) {
> > -		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
> > -							  send_bytes,
> > -							  aux_clock_divider);
> > -
> > -		send_ctl |= aux_send_ctl_flags;
> 
> You can't move the send_ctl assignment outside the loop, because the loop
> changes aux_clock_divider which affects send_ctl.
> 
> Please take your time with the next version, and don't try to rush it, and we'll
> get this done quicker.

Sure.

> 
> > -
> > -		/* Must try at least 3 times according to DP spec */
> > +		/* Re-visit : Must try at least 3 times according to DP spec */
> 
> How is this change helpful?

There was a comment on the earlier patch for the retry count. Here we are retrying for 5 times but the spec says retry for 3 times. Need to revisit this to see if there is any WA/recommendation in Bspec and to update the same with link or revert it to 3 times.

> 
> >  		for (try = 0; try < 5; try++) {
> > +			/* Try to wait for any previous AUX channel activity
> */
> > +			status = intel_dp_aux_wait_done(intel_dp);
> > +			/* just trace the final value */
> > +			trace_i915_reg_rw(false, ch_ctl, status, sizeof(status),
> true);
> > +
> > +			if (status & DP_AUX_CH_CTL_SEND_BUSY) {
> > +				drm_WARN(&i915->drm, 1,
> > +					 "%s: not started, previous Tx still in
> process (status 0x%08x)\n",
> > +					 intel_dp->aux.name, status);
> > +				intel_dp->aux_busy_last_status = status;
> > +				if (try > 3) {
> > +					ret = -EBUSY;
> > +					goto out;
> > +				} else
> > +					continue;
> 
> If one branch needs braces, all of them do.
> 
Ok.

Thanks and Regards,
Arun R Murthy
--------------------
> > +			}
> > +
> >  			/* Load the send data into the aux channel data
> registers */
> >  			for (i = 0; i < send_bytes; i += 4)
> >  				intel_de_write(i915, ch_data[i >> 2], @@ -
> 321,6 +313,7 @@
> > intel_dp_aux_xfer(struct intel_dp *intel_dp,
> >  			/* Send the command and wait for it to complete */
> >  			intel_de_write(i915, ch_ctl, send_ctl);
> >
> > +			/* TODO: if typeC then 4.2ms else 800us. For DG2
> add 1.5ms for
> > +both cases */
> >  			status = intel_dp_aux_wait_done(intel_dp);
> >
> >  			/* Clear done status and any errors */ @@ -335,7
> +328,8 @@
> > intel_dp_aux_xfer(struct intel_dp *intel_dp,
> >  			 *   Timeout errors from the HW already meet this
> >  			 *   requirement so skip to next iteration
> >  			 */
> > -			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
> > +			if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
> > +
> 	DP_AUX_CH_CTL_SEND_BUSY))
> 
> The indentation is off.
> 
> >  				continue;
> >
> >  			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
> 
> --
> Jani Nikula, Intel Open Source Graphics Center
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
index 21b50a5c8a85..abe8047fac39 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
@@ -226,6 +226,7 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 	int i, ret, recv_bytes;
 	int try, clock = 0;
 	u32 status;
+	u32 send_ctl;
 	bool vdd;
 
 	ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
@@ -273,45 +274,36 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 	 * it using the same AUX CH simultaneously
 	 */
 
-	/* Try to wait for any previous AUX channel activity */
-	for (try = 0; try < 3; try++) {
-		status = intel_de_read_notrace(i915, ch_ctl);
-		if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
-			break;
-		msleep(1);
-	}
-	/* just trace the final value */
-	trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
-
-	if (try == 3) {
-		const u32 status = intel_de_read(i915, ch_ctl);
-
-		if (status != intel_dp->aux_busy_last_status) {
-			drm_WARN(&i915->drm, 1,
-				 "%s: not started (status 0x%08x)\n",
-				 intel_dp->aux.name, status);
-			intel_dp->aux_busy_last_status = status;
-		}
-
-		ret = -EBUSY;
-		goto out;
-	}
-
 	/* Only 5 data registers! */
 	if (drm_WARN_ON(&i915->drm, send_bytes > 20 || recv_size > 20)) {
 		ret = -E2BIG;
 		goto out;
 	}
+	send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
+					      send_bytes,
+					      aux_clock_divider);
+	send_ctl |= aux_send_ctl_flags;
 
 	while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
-		u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
-							  send_bytes,
-							  aux_clock_divider);
-
-		send_ctl |= aux_send_ctl_flags;
-
-		/* Must try at least 3 times according to DP spec */
+		/* Re-visit : Must try at least 3 times according to DP spec */
 		for (try = 0; try < 5; try++) {
+			/* Try to wait for any previous AUX channel activity */
+			status = intel_dp_aux_wait_done(intel_dp);
+			/* just trace the final value */
+			trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
+
+			if (status & DP_AUX_CH_CTL_SEND_BUSY) {
+				drm_WARN(&i915->drm, 1,
+					 "%s: not started, previous Tx still in process (status 0x%08x)\n",
+					 intel_dp->aux.name, status);
+				intel_dp->aux_busy_last_status = status;
+				if (try > 3) {
+					ret = -EBUSY;
+					goto out;
+				} else
+					continue;
+			}
+
 			/* Load the send data into the aux channel data registers */
 			for (i = 0; i < send_bytes; i += 4)
 				intel_de_write(i915, ch_data[i >> 2],
@@ -321,6 +313,7 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 			/* Send the command and wait for it to complete */
 			intel_de_write(i915, ch_ctl, send_ctl);
 
+			/* TODO: if typeC then 4.2ms else 800us. For DG2 add 1.5ms for both cases */
 			status = intel_dp_aux_wait_done(intel_dp);
 
 			/* Clear done status and any errors */
@@ -335,7 +328,8 @@  intel_dp_aux_xfer(struct intel_dp *intel_dp,
 			 *   Timeout errors from the HW already meet this
 			 *   requirement so skip to next iteration
 			 */
-			if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR)
+			if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
+						DP_AUX_CH_CTL_SEND_BUSY))
 				continue;
 
 			if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {