[PATCH v2 01/17] i2c: tegra: Make tegra_i2c_flush_fifos() usable in atomic transfer

From: Dmitry Osipenko
Date: Tue Sep 01 2020 - 17:11:44 EST


The tegra_i2c_flush_fifos() shouldn't sleep in atomic transfer and jiffies
are not updating if interrupts are disabled. Hence let's use proper delay
functions and use ktime API in order not to hang atomic transfer. Note
that this patch doesn't fix any known problem because normally FIFO is
flushed at the time of starting a new transfer.

Signed-off-by: Dmitry Osipenko <digetx@xxxxxxxxx>
---
drivers/i2c/busses/i2c-tegra.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 00d3e4d7a01e..aab58395fb71 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -470,7 +470,8 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)

static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
{
- unsigned long timeout = jiffies + HZ;
+ ktime_t ktime = ktime_get();
+ ktime_t ktimeout = ktime_add_ms(ktime, 1000);
unsigned int offset;
u32 mask, val;

@@ -489,13 +490,22 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
i2c_writel(i2c_dev, val, offset);

while (i2c_readl(i2c_dev, offset) & mask) {
- if (time_after(jiffies, timeout)) {
- dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
- return -ETIMEDOUT;
- }
- usleep_range(1000, 2000);
+ if (ktime_after(ktime, ktimeout))
+ goto err_timeout;
+
+ if (i2c_dev->is_curr_atomic_xfer)
+ mdelay(1);
+ else
+ fsleep(1000);
+
+ ktime = ktime_get();
}
return 0;
+
+err_timeout:
+ dev_err(i2c_dev->dev, "fifo flush timed out\n");
+
+ return -ETIMEDOUT;
}

static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
--
2.27.0