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