Skip to content

Commit 02b9aec

Browse files
dianderswsakernel
authored andcommitted
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 starting 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. Although problems were seen on the RX path, code inspection suggests that the TX should be changed too. Change it as well. Fixes: 37692de ("i2c: i2c-qcom-geni: Add bus driver for the Qualcomm GENI I2C controller") Signed-off-by: Douglas Anderson <[email protected]> Tested-by: Sai Prakash Ranjan <[email protected]> Reviewed-by: Akash Asthana <[email protected]> Reviewed-by: Stephen Boyd <[email protected]> Reviewed-by: Mukesh Kumar Savaliya <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent eb01597 commit 02b9aec

File tree

1 file changed

+4
-2
lines changed

1 file changed

+4
-2
lines changed

drivers/i2c/busses/i2c-qcom-geni.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,15 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
367367
geni_se_select_mode(se, GENI_SE_FIFO);
368368

369369
writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
370-
geni_se_setup_m_cmd(se, I2C_READ, m_param);
371370

372371
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
373372
geni_se_select_mode(se, GENI_SE_FIFO);
374373
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
375374
dma_buf = NULL;
376375
}
377376

377+
geni_se_setup_m_cmd(se, I2C_READ, m_param);
378+
378379
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
379380
if (!time_left)
380381
geni_i2c_abort_xfer(gi2c);
@@ -408,14 +409,15 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
408409
geni_se_select_mode(se, GENI_SE_FIFO);
409410

410411
writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
411-
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
412412

413413
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
414414
geni_se_select_mode(se, GENI_SE_FIFO);
415415
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
416416
dma_buf = NULL;
417417
}
418418

419+
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
420+
419421
if (!dma_buf) /* Get FIFO IRQ */
420422
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
421423

0 commit comments

Comments
 (0)