RE: [PATCH 3/5] i2c: xiic: Defer xiic_wakeup() and __xiic_start_xfer() in xiic_process()

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

 




> -----Original Message-----
> From: linux-i2c-owner@xxxxxxxxxxxxxxx <linux-i2c-owner@xxxxxxxxxxxxxxx> On
> Behalf Of Marek Vasut
> Sent: Saturday, June 13, 2020 8:38 PM
> To: linux-i2c@xxxxxxxxxxxxxxx
> Cc: Marek Vasut <marex@xxxxxxx>; Michal Simek <michals@xxxxxxxxxx>;
> Shubhrajyoti Datta <shubhraj@xxxxxxxxxx>; Wolfram Sang <wsa@xxxxxxxxxx>
> Subject: [PATCH 3/5] i2c: xiic: Defer xiic_wakeup() and __xiic_start_xfer() in
> xiic_process()
> 
> The __xiic_start_xfer() manipulates the interrupt flags, xiic_wakeup() may
> result in return from xiic_xfer() early. Defer both to the end of the
> xiic_process() interrupt thread, so that they are executed after all the other
> interrupt bits handling completed and once it completely safe to perform
> changes to the interrupt bits in the hardware.
> 
> Signed-off-by: Marek Vasut <marex@xxxxxxx>
> Cc: Michal Simek <michal.simek@xxxxxxxxxx>
> Cc: Shubhrajyoti Datta <shubhrajyoti.datta@xxxxxxxxxx>
> Cc: Wolfram Sang <wsa@xxxxxxxxxx>
> ---
>  drivers/i2c/busses/i2c-xiic.c | 37 ++++++++++++++++++++++++-----------
>  1 file changed, 26 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index
> 6db71c0fb6583..87eca9d46afd9 100644
> --- a/drivers/i2c/busses/i2c-xiic.c
> +++ b/drivers/i2c/busses/i2c-xiic.c
> @@ -373,6 +373,9 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
>  	struct xiic_i2c *i2c = dev_id;
>  	u32 pend, isr, ier;
>  	u32 clr = 0;
> +	int xfer_more = 0;
> +	int wakeup_req = 0;
> +	int wakeup_code = 0;
> 
>  	/* Get the interrupt Status from the IPIF. There is no clearing of
>  	 * interrupts in the IPIF. Interrupts must be cleared at the source.
> @@ -409,10 +412,14 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
>  		 */
>  		xiic_reinit(i2c);
> 
> -		if (i2c->rx_msg)
> -			xiic_wakeup(i2c, STATE_ERROR);
> -		if (i2c->tx_msg)
> -			xiic_wakeup(i2c, STATE_ERROR);
> +		if (i2c->rx_msg) {
> +			wakeup_req = 1;
> +			wakeup_code = STATE_ERROR;
> +		}
> +		if (i2c->tx_msg) {
> +			wakeup_req = 1;
> +			wakeup_code = STATE_ERROR;
> +		}
>  	}
>  	if (pend & XIIC_INTR_RX_FULL_MASK) {
>  		/* Receive register/FIFO is full */
> @@ -446,8 +453,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
>  				i2c->tx_msg++;
>  				dev_dbg(i2c->adap.dev.parent,
>  					"%s will start next...\n", __func__);
> -
> -				__xiic_start_xfer(i2c);
> +				xfer_more = 1;
>  			}
>  		}
>  	}
> @@ -461,11 +467,13 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
>  		if (!i2c->tx_msg)
>  			goto out;
> 
> -		if ((i2c->nmsgs == 1) && !i2c->rx_msg &&
> -			xiic_tx_space(i2c) == 0)
> -			xiic_wakeup(i2c, STATE_DONE);
> +		wakeup_req = 1;
> +
> +		if (i2c->nmsgs == 1 && !i2c->rx_msg &&
> +		    xiic_tx_space(i2c) == 0)
> +			wakeup_code = STATE_DONE;
>  		else
> -			xiic_wakeup(i2c, STATE_ERROR);
> +			wakeup_code = STATE_ERROR;
>  	}
>  	if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK))
> {
>  		/* Transmit register/FIFO is empty or ½ empty */ @@ -489,7
> +497,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
>  			if (i2c->nmsgs > 1) {
>  				i2c->nmsgs--;
>  				i2c->tx_msg++;
> -				__xiic_start_xfer(i2c);
> +				xfer_more = 1;
>  			} else {
>  				xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
> 
> @@ -507,6 +515,13 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
>  	dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
> 
>  	xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
> +	if (xfer_more)
> +		__xiic_start_xfer(i2c);
> +	if (wakeup_req)
> +		xiic_wakeup(i2c, wakeup_code);
> +
> +	WARN_ON(xfer_more && wakeup_req);
> +
>  	mutex_unlock(&i2c->lock);
>  	return IRQ_HANDLED;
>  }

This is tested and working fine.

Raviteja N





[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux