[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200720172448.1.I7efdf6efaa6edadbb690196cd4fbe3392a582c89@changeid>
Date: Mon, 20 Jul 2020 17:24:53 -0700
From: Douglas Anderson <dianders@...omium.org>
To: Wolfram Sang <wsa@...-dreams.de>
Cc: Sai Prakash Ranjan <saiprakash.ranjan@...eaurora.org>,
Rajendra Nayak <rnayak@...eaurora.org>, swboyd@...omium.org,
Akash Asthana <akashast@...eaurora.org>,
Douglas Anderson <dianders@...omium.org>,
Alok Chauhan <alokc@...eaurora.org>,
Andy Gross <agross@...nel.org>,
Bjorn Andersson <bjorn.andersson@...aro.org>,
Girish Mahadevan <girishm@...eaurora.org>,
Karthikeyan Ramasubramanian <kramasub@...eaurora.org>,
Wolfram Sang <wsa@...nel.org>, linux-arm-msm@...r.kernel.org,
linux-i2c@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH] i2c: i2c-qcom-geni: Fix DMA transfer race
When I have KASAN enabled on my kernel and I start stressing the
touchscreen my system tends to hang. The touchscreen is one of the
only things that does a lot of big i2c transfers and ends up hitting
the DMA paths in the geni i2c driver. It appears that KASAN adds
enough delay in my system to tickle a race condition in the DMA setup
code.
When the system hangs, I found that it was running the geni_i2c_irq()
over and over again. It had these:
m_stat = 0x04000080
rx_st = 0x30000011
dm_tx_st = 0x00000000
dm_rx_st = 0x00000000
dma = 0x00000001
Notably we're in DMA mode but are getting M_RX_IRQ_EN and
M_RX_FIFO_WATERMARK_EN over and over again.
Putting some traces in geni_i2c_rx_one_msg() showed that when we
failed we were getting to the start of geni_i2c_rx_one_msg() but were
never executing geni_se_rx_dma_prep().
I believe that the problem here is that we are writing the transfer
length and setting up the geni command before we run
geni_se_rx_dma_prep(). If a transfer makes it far enough before we do
that then we get into the state I have observed. Let's change the
order, which seems to work fine.
Fixes: 37692de5d523 ("i2c: i2c-qcom-geni: Add bus driver for the Qualcomm GENI I2C controller")
Signed-off-by: Douglas Anderson <dianders@...omium.org>
---
drivers/i2c/busses/i2c-qcom-geni.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 18d1e4fd4cf3..21e27f10510a 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -366,15 +366,15 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
else
geni_se_select_mode(se, GENI_SE_FIFO);
- writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
- geni_se_setup_m_cmd(se, I2C_READ, m_param);
-
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
geni_se_select_mode(se, GENI_SE_FIFO);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
dma_buf = NULL;
}
+ writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_READ, m_param);
+
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
--
2.28.0.rc0.142.g3c755180ce-goog
Powered by blists - more mailing lists