RE: [PATCH 4/5] i2c: xiic: Switch from waitqueue to completion

[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 4/5] i2c: xiic: Switch from waitqueue to completion
> 
> There will never be threads queueing up in the xiic_xmit(), use completion
> synchronization primitive to wait for the interrupt handler thread to complete
> instead as it is much better fit and there is no need to overload it for this
> purpose.
> 
> 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 | 31 ++++++++++++++++---------------
>  1 file changed, 16 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index
> 87eca9d46afd9..e4c3427b2f3f5 100644
> --- a/drivers/i2c/busses/i2c-xiic.c
> +++ b/drivers/i2c/busses/i2c-xiic.c
> @@ -23,7 +23,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/i2c.h>
>  #include <linux/interrupt.h>
> -#include <linux/wait.h>
> +#include <linux/completion.h>
>  #include <linux/platform_data/i2c-xiic.h>  #include <linux/io.h>  #include
> <linux/slab.h> @@ -48,7 +48,7 @@ enum xiic_endian {
>   * struct xiic_i2c - Internal representation of the XIIC I2C bus
>   * @dev:	Pointer to device structure
>   * @base:	Memory base of the HW registers
> - * @wait:	Wait queue for callers
> + * @completion:	Completion for callers
>   * @adap:	Kernel adapter representation
>   * @tx_msg:	Messages from above to be sent
>   * @lock:	Mutual exclusion
> @@ -63,7 +63,7 @@ enum xiic_endian {
>  struct xiic_i2c {
>  	struct device		*dev;
>  	void __iomem		*base;
> -	wait_queue_head_t	wait;
> +	struct completion	completion;
>  	struct i2c_adapter	adap;
>  	struct i2c_msg		*tx_msg;
>  	struct mutex		lock;
> @@ -365,7 +365,7 @@ static void xiic_wakeup(struct xiic_i2c *i2c, int code)
>  	i2c->rx_msg = NULL;
>  	i2c->nmsgs = 0;
>  	i2c->state = code;
> -	wake_up(&i2c->wait);
> +	complete(&i2c->completion);
>  }
> 
>  static irqreturn_t xiic_process(int irq, void *dev_id) @@ -677,6 +677,7 @@
> static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
> 
>  	i2c->tx_msg = msgs;
>  	i2c->nmsgs = num;
> +	init_completion(&i2c->completion);
> 
>  	ret = xiic_reinit(i2c);
>  	if (!ret)
> @@ -703,23 +704,24 @@ static int xiic_xfer(struct i2c_adapter *adap, struct
> i2c_msg *msgs, int num)
>  	err = xiic_start_xfer(i2c, msgs, num);
>  	if (err < 0) {
>  		dev_err(adap->dev.parent, "Error xiic_start_xfer\n");
> -		goto out;
> +		return err;
>  	}
> 
> -	if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
> -		(i2c->state == STATE_DONE), HZ)) {
> -		mutex_lock(&i2c->lock);
> -		err = (i2c->state == STATE_DONE) ? num : -EIO;
> -		goto out;
> -	} else {
> -		mutex_lock(&i2c->lock);
> +	err = wait_for_completion_interruptible_timeout(&i2c->completion,
> +							XIIC_I2C_TIMEOUT);

This is causing random lock up of bus. Since it is "interruptible" API,  once we enter Ctrl+C, 
It is coming out of wait state, the message pointers are made NULL and the ongoing transaction is not completed. 
Can use " wait_for_completion_timeout" API in place of this.

> +	mutex_lock(&i2c->lock);
> +	if (err == 0) {	/* Timeout */
>  		i2c->tx_msg = NULL;
>  		i2c->rx_msg = NULL;
>  		i2c->nmsgs = 0;
>  		err = -ETIMEDOUT;
> -		goto out;
> +	} else if (err < 0) {	/* Completion error */
> +		i2c->tx_msg = NULL;
> +		i2c->rx_msg = NULL;
> +		i2c->nmsgs = 0;
> +	} else {
> +		err = (i2c->state == STATE_DONE) ? num : -EIO;
>  	}
> -out:
>  	mutex_unlock(&i2c->lock);
>  	pm_runtime_mark_last_busy(i2c->dev);
>  	pm_runtime_put_autosuspend(i2c->dev);
> @@ -781,7 +783,6 @@ static int xiic_i2c_probe(struct platform_device *pdev)
>  	i2c->adap.dev.of_node = pdev->dev.of_node;
> 
>  	mutex_init(&i2c->lock);
> -	init_waitqueue_head(&i2c->wait);
> 
>  	i2c->clk = devm_clk_get(&pdev->dev, NULL);
>  	if (IS_ERR(i2c->clk)) {

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