Skip to content

Commit 6697576

Browse files
bebarinoWolfram Sang
authored andcommitted
i2c: i2c-qcom-geni: Properly handle DMA safe buffers
We shouldn't attempt to DMA map the message buffers passed into this driver from the i2c core unless the message we're mapping have been properly setup for DMA. The i2c core indicates such a situation by setting the I2C_M_DMA_SAFE flag, so check for that flag before using DMA mode. We can also bounce the buffer if it isn't already mapped properly by using the i2c_get_dma_safe_msg_buf() APIs, so do that when we want to use DMA for a message. This fixes a problem where the kernel oopses cleaning pages for a buffer that's mapped into the vmalloc space. The pages are returned from request_firmware() and passed down directly to the i2c master to write to the i2c touchscreen device. Mapping vmalloc buffers with dma_map_single() won't work reliably, causing an oops like below: Unable to handle kernel paging request at virtual address ffffffc01391d000 ... Reported-by: Philip Chen <philipchen@chromium.org> Signed-off-by: Stephen Boyd <swboyd@chromium.org> Reviewed-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
1 parent 6bf4ca7 commit 6697576

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,20 +367,26 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
367367
dma_addr_t rx_dma;
368368
enum geni_se_xfer_mode mode;
369369
unsigned long time_left = XFER_TIMEOUT;
370+
void *dma_buf;
370371

371372
gi2c->cur = msg;
372-
mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
373+
mode = GENI_SE_FIFO;
374+
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
375+
if (dma_buf)
376+
mode = GENI_SE_DMA;
377+
373378
geni_se_select_mode(&gi2c->se, mode);
374379
writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN);
375380
geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param);
376381
if (mode == GENI_SE_DMA) {
377382
int ret;
378383

379-
ret = geni_se_rx_dma_prep(&gi2c->se, msg->buf, msg->len,
384+
ret = geni_se_rx_dma_prep(&gi2c->se, dma_buf, msg->len,
380385
&rx_dma);
381386
if (ret) {
382387
mode = GENI_SE_FIFO;
383388
geni_se_select_mode(&gi2c->se, mode);
389+
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
384390
}
385391
}
386392

@@ -393,6 +399,7 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
393399
if (gi2c->err)
394400
geni_i2c_rx_fsm_rst(gi2c);
395401
geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len);
402+
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
396403
}
397404
return gi2c->err;
398405
}
@@ -403,20 +410,26 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
403410
dma_addr_t tx_dma;
404411
enum geni_se_xfer_mode mode;
405412
unsigned long time_left;
413+
void *dma_buf;
406414

407415
gi2c->cur = msg;
408-
mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
416+
mode = GENI_SE_FIFO;
417+
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
418+
if (dma_buf)
419+
mode = GENI_SE_DMA;
420+
409421
geni_se_select_mode(&gi2c->se, mode);
410422
writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN);
411423
geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param);
412424
if (mode == GENI_SE_DMA) {
413425
int ret;
414426

415-
ret = geni_se_tx_dma_prep(&gi2c->se, msg->buf, msg->len,
427+
ret = geni_se_tx_dma_prep(&gi2c->se, dma_buf, msg->len,
416428
&tx_dma);
417429
if (ret) {
418430
mode = GENI_SE_FIFO;
419431
geni_se_select_mode(&gi2c->se, mode);
432+
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
420433
}
421434
}
422435

@@ -432,6 +445,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
432445
if (gi2c->err)
433446
geni_i2c_tx_fsm_rst(gi2c);
434447
geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len);
448+
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
435449
}
436450
return gi2c->err;
437451
}

0 commit comments

Comments
 (0)