2019-11-19 06:13:58

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 4.19 127/422] i2c: mediatek: Use DMA safe buffers for i2c transactions

From: Jun Gao <[email protected]>

[ Upstream commit fc66b39fe36acfd06f716e338de7cd8f9550fad2 ]

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 <[email protected]>
Signed-off-by: Wolfram Sang <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
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 1e57f58fcb001..a74ef76705e0c 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 = NULL;
+ u8 *dma_wr_buf = NULL;
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_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
+
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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+
+ 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
+
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_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
} else if (i2c->op == I2C_MASTER_RD) {
dma_unmap_single(i2c->dev, rpaddr,
msgs->len, DMA_FROM_DEVICE);
+
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
} 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
+ i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
}

if (ret == 0) {
--
2.20.1




2019-11-20 02:13:46

by Nobuhiro Iwamatsu

[permalink] [raw]
Subject: Re: [PATCH 4.19 127/422] i2c: mediatek: Use DMA safe buffers for i2c transactions

Hi,

On Tue, Nov 19, 2019 at 06:15:24AM +0100, Greg Kroah-Hartman wrote:
> From: Jun Gao <[email protected]>
>
> [ Upstream commit fc66b39fe36acfd06f716e338de7cd8f9550fad2 ]
>
> 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 <[email protected]>
> Signed-off-by: Wolfram Sang <[email protected]>
> Signed-off-by: Sasha Levin <[email protected]>

This patch requires the following additional commit:

commit bc1a7f75c85e226e82f183d30d75c357f92b6029
Author: Hsin-Yi Wang <[email protected]>
Date: Fri Feb 15 17:02:02 2019 +0800

i2c: mediatek: modify threshold passed to i2c_get_dma_safe_msg_buf()

DMA with zero-length transfers doesn't make sense and this HW doesn't
support them at all, so increase the threshold.

Fixes: fc66b39fe36a ("i2c: mediatek: Use DMA safe buffers for i2c transactions")
Signed-off-by: Hsin-Yi Wang <[email protected]>
[wsa: reworded commit message]
Signed-off-by: Wolfram Sang <[email protected]>

Please apply this commit.

Best regards,
Nobuhiro

> ---
> 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 1e57f58fcb001..a74ef76705e0c 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 = NULL;
> + u8 *dma_wr_buf = NULL;
> 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_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
> +
> 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> +
> 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> +
> 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> +
> + 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> + i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
> +
> 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
> } else if (i2c->op == I2C_MASTER_RD) {
> dma_unmap_single(i2c->dev, rpaddr,
> msgs->len, DMA_FROM_DEVICE);
> +
> + i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
> } 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
> + i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
> }
>
> if (ret == 0) {
> --
> 2.20.1
>
>
>
>

2019-11-21 06:55:25

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 4.19 127/422] i2c: mediatek: Use DMA safe buffers for i2c transactions

On Wed, Nov 20, 2019 at 10:44:06AM +0900, Nobuhiro Iwamatsu wrote:
> Hi,
>
> On Tue, Nov 19, 2019 at 06:15:24AM +0100, Greg Kroah-Hartman wrote:
> > From: Jun Gao <[email protected]>
> >
> > [ Upstream commit fc66b39fe36acfd06f716e338de7cd8f9550fad2 ]
> >
> > 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 <[email protected]>
> > Signed-off-by: Wolfram Sang <[email protected]>
> > Signed-off-by: Sasha Levin <[email protected]>
>
> This patch requires the following additional commit:
>
> commit bc1a7f75c85e226e82f183d30d75c357f92b6029
> Author: Hsin-Yi Wang <[email protected]>
> Date: Fri Feb 15 17:02:02 2019 +0800
>
> i2c: mediatek: modify threshold passed to i2c_get_dma_safe_msg_buf()
>
> DMA with zero-length transfers doesn't make sense and this HW doesn't
> support them at all, so increase the threshold.
>
> Fixes: fc66b39fe36a ("i2c: mediatek: Use DMA safe buffers for i2c transactions")
> Signed-off-by: Hsin-Yi Wang <[email protected]>
> [wsa: reworded commit message]
> Signed-off-by: Wolfram Sang <[email protected]>
>
> Please apply this commit.
>
> Best regards,
> Nobuhiro
>
> > ---
> > 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 1e57f58fcb001..a74ef76705e0c 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 = NULL;
> > + u8 *dma_wr_buf = NULL;
> > 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_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
> > +
> > 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> > +
> > 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> > +
> > 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> > +
> > + 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
> > + i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
> > +
> > 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
> > } else if (i2c->op == I2C_MASTER_RD) {
> > dma_unmap_single(i2c->dev, rpaddr,
> > msgs->len, DMA_FROM_DEVICE);
> > +
> > + i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
> > } 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_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
> > + i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
> > }
> >
> > if (ret == 0) {
> > --
> > 2.20.1

Now queued up, thanks.

greg k-h