From: Jun Gao <jun....@mediatek.com>

DMA mode will always be used in i2c transactions, try to allocate
a DMA safe buffer if the buf of struct i2c_msg used is not DMA safe.

Signed-off-by: Jun Gao <jun....@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 62 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 806e8b90..dd014ee 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -441,6 +441,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct 
i2c_msg *msgs,
        u16 control_reg;
        u16 restart_flag = 0;
        u32 reg_4g_mode;
+       u8 *dma_rd_buf;
+       u8 *dma_wr_buf;
        dma_addr_t rpaddr = 0;
        dma_addr_t wpaddr = 0;
        int ret;
@@ -500,10 +502,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, 
struct i2c_msg *msgs,
        if (i2c->op == I2C_MASTER_RD) {
                writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
                writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON);
-               rpaddr = dma_map_single(i2c->dev, msgs->buf,
+
+               dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
+               if (!dma_rd_buf)
+                       return -ENOMEM;
+
+               rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
                                        msgs->len, DMA_FROM_DEVICE);
-               if (dma_mapping_error(i2c->dev, rpaddr))
+               if (dma_mapping_error(i2c->dev, rpaddr)) {
+                       i2c_free_dma_safe_msg_buf(msgs, dma_rd_buf);
+
                        return -ENOMEM;
+               }
 
                if (i2c->dev_comp->support_33bits) {
                        reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
@@ -515,10 +525,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, 
struct i2c_msg *msgs,
        } else if (i2c->op == I2C_MASTER_WR) {
                writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
                writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON);
-               wpaddr = dma_map_single(i2c->dev, msgs->buf,
+
+               dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
+               if (!dma_wr_buf)
+                       return -ENOMEM;
+
+               wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
                                        msgs->len, DMA_TO_DEVICE);
-               if (dma_mapping_error(i2c->dev, wpaddr))
+               if (dma_mapping_error(i2c->dev, wpaddr)) {
+                       i2c_free_dma_safe_msg_buf(msgs, dma_wr_buf);
+
                        return -ENOMEM;
+               }
 
                if (i2c->dev_comp->support_33bits) {
                        reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
@@ -530,16 +548,39 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, 
struct i2c_msg *msgs,
        } else {
                writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
                writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON);
-               wpaddr = dma_map_single(i2c->dev, msgs->buf,
+
+               dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
+               if (!dma_wr_buf)
+                       return -ENOMEM;
+
+               wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
                                        msgs->len, DMA_TO_DEVICE);
-               if (dma_mapping_error(i2c->dev, wpaddr))
+               if (dma_mapping_error(i2c->dev, wpaddr)) {
+                       i2c_free_dma_safe_msg_buf(msgs, dma_wr_buf);
+
                        return -ENOMEM;
-               rpaddr = dma_map_single(i2c->dev, (msgs + 1)->buf,
+               }
+
+               dma_rd_buf = i2c_get_dma_safe_msg_buf((msgs + 1), 0);
+               if (!dma_rd_buf) {
+                       dma_unmap_single(i2c->dev, wpaddr,
+                                        msgs->len, DMA_TO_DEVICE);
+
+                       i2c_free_dma_safe_msg_buf(msgs, dma_wr_buf);
+
+                       return -ENOMEM;
+               }
+
+               rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
                                        (msgs + 1)->len,
                                        DMA_FROM_DEVICE);
                if (dma_mapping_error(i2c->dev, rpaddr)) {
                        dma_unmap_single(i2c->dev, wpaddr,
                                         msgs->len, DMA_TO_DEVICE);
+
+                       i2c_free_dma_safe_msg_buf(msgs, dma_wr_buf);
+                       i2c_free_dma_safe_msg_buf((msgs + 1), dma_rd_buf);
+
                        return -ENOMEM;
                }
 
@@ -578,14 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, 
struct i2c_msg *msgs,
        if (i2c->op == I2C_MASTER_WR) {
                dma_unmap_single(i2c->dev, wpaddr,
                                 msgs->len, DMA_TO_DEVICE);
+
+               i2c_release_dma_safe_msg_buf(msgs, dma_wr_buf);
        } else if (i2c->op == I2C_MASTER_RD) {
                dma_unmap_single(i2c->dev, rpaddr,
                                 msgs->len, DMA_FROM_DEVICE);
+
+               i2c_release_dma_safe_msg_buf(msgs, dma_rd_buf);
        } else {
                dma_unmap_single(i2c->dev, wpaddr, msgs->len,
                                 DMA_TO_DEVICE);
                dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len,
                                 DMA_FROM_DEVICE);
+
+               i2c_release_dma_safe_msg_buf(msgs, dma_wr_buf);
+               i2c_release_dma_safe_msg_buf((msgs + 1), dma_rd_buf);
        }
 
        if (ret == 0) {
-- 
1.8.1.1

Reply via email to