mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 13:44:15 +08:00
i2c: mxs: ensure that DMA buffers are safe for DMA
We found that after commit9c46929e79
("ARM: implement THREAD_INFO_IN_TASK for uniprocessor systems"), the PCF85063 RTC driver stopped working on i.MX28 due to regmap_bulk_read() reading bogus data into a stack buffer. This is caused by the i2c-mxs driver using DMA transfers even for messages without the I2C_M_DMA_SAFE flag, and the aforementioned commit enabling vmapped stacks. As the MXS I2C controller requires DMA for reads of >4 bytes, DMA can't be disabled, so the issue is fixed by using i2c_get_dma_safe_msg_buf() to create a bounce buffer when needed. Fixes:9c46929e79
("ARM: implement THREAD_INFO_IN_TASK for uniprocessor systems") Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
This commit is contained in:
parent
1c78850045
commit
5190417bdf
@ -171,7 +171,7 @@ static void mxs_i2c_dma_irq_callback(void *param)
|
||||
}
|
||||
|
||||
static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, uint32_t flags)
|
||||
struct i2c_msg *msg, u8 *buf, uint32_t flags)
|
||||
{
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
|
||||
@ -226,7 +226,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
|
||||
}
|
||||
|
||||
/* Queue the DMA data transfer. */
|
||||
sg_init_one(&i2c->sg_io[1], msg->buf, msg->len);
|
||||
sg_init_one(&i2c->sg_io[1], buf, msg->len);
|
||||
dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
|
||||
desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
|
||||
DMA_DEV_TO_MEM,
|
||||
@ -259,7 +259,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
|
||||
/* Queue the DMA data transfer. */
|
||||
sg_init_table(i2c->sg_io, 2);
|
||||
sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1);
|
||||
sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len);
|
||||
sg_set_buf(&i2c->sg_io[1], buf, msg->len);
|
||||
dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
|
||||
desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
|
||||
DMA_MEM_TO_DEV,
|
||||
@ -563,6 +563,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
|
||||
int ret;
|
||||
int flags;
|
||||
u8 *dma_buf;
|
||||
int use_pio = 0;
|
||||
unsigned long time_left;
|
||||
|
||||
@ -588,13 +589,20 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
if (ret && (ret != -ENXIO))
|
||||
mxs_i2c_reset(i2c);
|
||||
} else {
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 1);
|
||||
if (!dma_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
reinit_completion(&i2c->cmd_complete);
|
||||
ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
|
||||
if (ret)
|
||||
ret = mxs_i2c_dma_setup_xfer(adap, msg, dma_buf, flags);
|
||||
if (ret) {
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c->cmd_complete,
|
||||
msecs_to_jiffies(1000));
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, true);
|
||||
if (!time_left)
|
||||
goto timeout;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user