When del_timer_sync() is called in an interrupt context it throws a warning
because of potential deadlock. The timer is used only to exit from
wait_for_completion() after a timeout so replacing the call with
wait_for_completion_timeout() allows to remove the problematic timer and
its related functions altogether.

Signed-off-by: Piotr Wojtaszczyk <piotr.wojtaszc...@timesys.com>
---
Changes for v5:
- Replaced wait_for_completion() with wait_for_completion_timeout().
- Removed unneded "alg_data->mif.timer" and its functions
- Request irq with devm_request_irq() as before the patch
- Renamed the patch and reword description for the new way to fix
  the warning

Changes for v4:
- Request irq with devm_request_threaded_irq() to prevent the warning

 drivers/i2c/busses/i2c-pnx.c | 48 ++++++++----------------------------
 1 file changed, 10 insertions(+), 38 deletions(-)

diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index a12525b3186b..f448505d5468 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -15,7 +15,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/timer.h>
 #include <linux/completion.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -32,7 +31,6 @@ struct i2c_pnx_mif {
        int                     ret;            /* Return value */
        int                     mode;           /* Interface mode */
        struct completion       complete;       /* I/O completion */
-       struct timer_list       timer;          /* Timeout */
        u8 *                    buf;            /* Data buffer */
        int                     len;            /* Length of data buffer */
        int                     order;          /* RX Bytes to order via TX */
@@ -117,24 +115,6 @@ static inline int wait_reset(struct i2c_pnx_algo_data 
*data)
        return (timeout <= 0);
 }
 
-static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
-{
-       struct timer_list *timer = &alg_data->mif.timer;
-       unsigned long expires = msecs_to_jiffies(alg_data->timeout);
-
-       if (expires <= 1)
-               expires = 2;
-
-       del_timer_sync(timer);
-
-       dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu 
jiffies.\n",
-               jiffies, expires);
-
-       timer->expires = jiffies + expires;
-
-       add_timer(timer);
-}
-
 /**
  * i2c_pnx_start - start a device
  * @slave_addr:                slave address
@@ -259,8 +239,6 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data 
*alg_data)
                                ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
                                  I2C_REG_CTL(alg_data));
 
-                       del_timer_sync(&alg_data->mif.timer);
-
                        dev_dbg(&alg_data->adapter.dev,
                                "%s(): Waking up xfer routine.\n",
                                __func__);
@@ -276,8 +254,6 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data 
*alg_data)
                        ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
                          I2C_REG_CTL(alg_data));
 
-               /* Stop timer. */
-               del_timer_sync(&alg_data->mif.timer);
                dev_dbg(&alg_data->adapter.dev,
                        "%s(): Waking up xfer routine after zero-xfer.\n",
                        __func__);
@@ -364,8 +340,6 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data 
*alg_data)
                                 mcntrl_drmie | mcntrl_daie);
                        iowrite32(ctl, I2C_REG_CTL(alg_data));
 
-                       /* Kill timer. */
-                       del_timer_sync(&alg_data->mif.timer);
                        complete(&alg_data->mif.complete);
                }
        }
@@ -400,8 +374,6 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
                         mcntrl_drmie);
                iowrite32(ctl, I2C_REG_CTL(alg_data));
 
-               /* Stop timer, to prevent timeout. */
-               del_timer_sync(&alg_data->mif.timer);
                complete(&alg_data->mif.complete);
        } else if (stat & mstatus_nai) {
                /* Slave did not acknowledge, generate a STOP */
@@ -419,8 +391,6 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
                /* Our return value. */
                alg_data->mif.ret = -EIO;
 
-               /* Stop timer, to prevent timeout. */
-               del_timer_sync(&alg_data->mif.timer);
                complete(&alg_data->mif.complete);
        } else {
                /*
@@ -453,9 +423,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void i2c_pnx_timeout(struct timer_list *t)
+static void i2c_pnx_timeout(struct i2c_pnx_algo_data *alg_data)
 {
-       struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer);
        u32 ctl;
 
        dev_err(&alg_data->adapter.dev,
@@ -472,7 +441,6 @@ static void i2c_pnx_timeout(struct timer_list *t)
        iowrite32(ctl, I2C_REG_CTL(alg_data));
        wait_reset(alg_data);
        alg_data->mif.ret = -EIO;
-       complete(&alg_data->mif.complete);
 }
 
 static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
@@ -514,6 +482,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg 
*msgs, int num)
        struct i2c_msg *pmsg;
        int rc = 0, completed = 0, i;
        struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+       unsigned long time_left;
        u32 stat;
 
        dev_dbg(&alg_data->adapter.dev,
@@ -548,7 +517,6 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg 
*msgs, int num)
                dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
                        __func__, alg_data->mif.mode, alg_data->mif.len);
 
-               i2c_pnx_arm_timer(alg_data);
 
                /* initialize the completion var */
                init_completion(&alg_data->mif.complete);
@@ -564,7 +532,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg 
*msgs, int num)
                        break;
 
                /* Wait for completion */
-               wait_for_completion(&alg_data->mif.complete);
+               time_left = wait_for_completion_timeout(&alg_data->mif.complete,
+                                                       alg_data->timeout);
+               if (time_left == 0)
+                       i2c_pnx_timeout(alg_data);
 
                if (!(rc = alg_data->mif.ret))
                        completed++;
@@ -653,7 +624,10 @@ static int i2c_pnx_probe(struct platform_device *pdev)
        alg_data->adapter.algo_data = alg_data;
        alg_data->adapter.nr = pdev->id;
 
-       alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
+       alg_data->timeout = msecs_to_jiffies(I2C_PNX_TIMEOUT_DEFAULT);
+       if (alg_data->timeout <= 1)
+               alg_data->timeout = 2;
+
 #ifdef CONFIG_OF
        alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
        if (pdev->dev.of_node) {
@@ -673,8 +647,6 @@ static int i2c_pnx_probe(struct platform_device *pdev)
        if (IS_ERR(alg_data->clk))
                return PTR_ERR(alg_data->clk);
 
-       timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0);
-
        snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
                 "%s", pdev->name);
 
-- 
2.25.1

Reply via email to