vl53l1: fix i2c dma transfer crash

If the i2c master starts the dma transfer,
the buffer must be physical continous. or i2c_transfer will crash.

__dma_inv_area+0x28/0x58
geni_se_rx_dma_prep+0xb0/0x208
geni_i2c_xfer+0x2e8/0xf88
__i2c_transfer+0x598/0x790
i2c_transfer+0xa0/0xe8
cci_read.isra.1+0xa4/0x140 [stmvl53l1]
VL53L1_ReadMulti+0x3c/0x54 [stmvl53l1]
VL53L1_get_nvm_copy_data+0x40/0x88 [stmvl53l1]
VL53L1_read_p2p_data+0xbc/0x210 [stmvl53l1]
VL53L1_data_init+0x248/0x254 [stmvl53l1]
VL53L1_DataInit+0x28/0xcc [stmvl53l1]
stmvl53l1_setup+0x4a8/0x9f0 [stmvl53l1]
stmvl53l1_probe+0x1e4/0x8c8 [stmvl53l1]
i2c_device_probe+0x258/0x2e0
driver_probe_device+0x4c0/0x658
__driver_attach+0x104/0x1b0
bus_for_each_dev+0x8c/0xd8
driver_attach+0x2c/0x38
bus_add_driver+0x138/0x240
driver_register+0xac/0xf8
i2c_register_driver+0x4c/0xd0
stmvl53l1_init_i2c+0x44/0x188 [stmvl53l1]
stmvl53l1_init+0x3c/0x1000 [stmvl53l1]

Change-Id: I8c328f1e5187dbd1de80aa700aa560ef29a9ed4d
Signed-off-by: liuyc20 <liuyc20@lenovo.com>
Reviewed-on: https://gerrit.mot.com/1377597
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Reviewed-by: Dawei Wang <wangdw10@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
liuyc20 2019-06-27 16:05:01 +08:00 • committed by Yuecai Liu
commit e388a3537b
3 changed files with 52 additions and 6 deletions

View file

@ -93,6 +93,12 @@ struct i2c_data {
struct msgtctrl_t {
unsigned unhandled_irq_vec:1;
} msg_flag;
struct i2c_dma_data {
struct mutex lock;
uint8_t *data;
unsigned int len;
} dma_data;
};
int stmvl53l1_init_i2c(void);

View file

@ -111,7 +111,6 @@ static uint32_t tv_elapsed_ms(struct timeval *tv)
static int cci_write(struct stmvl53l1_data *dev, int index,
uint8_t *data, uint16_t len)
{
uint8_t buffer[STMVL53L1_MAX_CCI_XFER_SZ + 2];
struct i2c_msg msg;
struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object;
struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client;
@ -122,16 +121,30 @@ static int cci_write(struct stmvl53l1_data *dev, int index,
vl53l1_errmsg("invalid len %d\n", len);
return -1;
}
mutex_lock(&i2c_client_obj->dma_data.lock);
if (i2c_client_obj->dma_data.len < len + 2) {
if (i2c_client_obj->dma_data.data)
kfree(i2c_client_obj->dma_data.data);
i2c_client_obj->dma_data.data = kzalloc(len + 2, GFP_KERNEL);
if (!i2c_client_obj->dma_data.data) {
i2c_client_obj->dma_data.len = 0;
mutex_unlock(&i2c_client_obj->dma_data.lock);
return -1;
}
i2c_client_obj->dma_data.len = len + 2;
}
cci_access_start();
/* build up little endian index in buffer */
buffer[0] = (index >> 8) & 0xFF;
buffer[1] = (index >> 0) & 0xFF;
i2c_client_obj->dma_data.data[0] = (index >> 8) & 0xFF;
i2c_client_obj->dma_data.data[1] = (index >> 0) & 0xFF;
/* copy write data to buffer after index */
memcpy(buffer + 2, data, len);
memcpy(i2c_client_obj->dma_data.data + 2, data, len);
/* set i2c msg */
msg.addr = client->addr;
msg.flags = client->flags;
msg.buf = buffer;
msg.buf = i2c_client_obj->dma_data.data;
msg.len = len + 2;
rc = i2c_transfer(client->adapter, &msg, 1);
@ -139,6 +152,9 @@ static int cci_write(struct stmvl53l1_data *dev, int index,
vl53l1_errmsg("wr i2c_transfer err:%d, index 0x%x len %d\n",
rc, index, len);
}
mutex_unlock(&i2c_client_obj->dma_data.lock);
cci_access_over("rd status %d long %d ", rc != 1, len);
return rc != 1;
}
@ -157,6 +173,20 @@ static int cci_read(struct stmvl53l1_data *dev, int index,
vl53l1_errmsg("invalid len %d\n", len);
return -1;
}
mutex_lock(&i2c_client_obj->dma_data.lock);
if (i2c_client_obj->dma_data.len < len) {
if (i2c_client_obj->dma_data.data)
kfree(i2c_client_obj->dma_data.data);
i2c_client_obj->dma_data.data = kzalloc(len, GFP_KERNEL);
if (!i2c_client_obj->dma_data.data) {
i2c_client_obj->dma_data.len = 0;
mutex_unlock(&i2c_client_obj->dma_data.lock);
return -1;
}
i2c_client_obj->dma_data.len = len;
}
cci_access_start();
/* build up little endian index in buffer */
@ -170,7 +200,7 @@ static int cci_read(struct stmvl53l1_data *dev, int index,
/* read part of the i2c transaction */
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD | client->flags;
msg[1].buf = data;
msg[1].buf = i2c_client_obj->dma_data.data;
msg[1].len = len;
rc = i2c_transfer(client->adapter, msg, 2);
@ -179,6 +209,10 @@ static int cci_read(struct stmvl53l1_data *dev, int index,
__func__, rc, client->addr, index, len);
}
memcpy(data, i2c_client_obj->dma_data.data, len);
mutex_unlock(&i2c_client_obj->dma_data.lock);
cci_access_over(" wr len %d status %d", rc != 2, len);
return rc != 2;
}

View file

@ -506,6 +506,8 @@ static int stmvl53l1_probe(struct i2c_client *client,
i2c_data->client = client;
i2c_data->vl53l1_data = vl53l1_data;
i2c_data->irq = -1 ; /* init to no irq */
i2c_data->dma_data.len = 0;
mutex_init(&i2c_data->dma_data.lock);
/* parse and configure hardware */
rc = stmvl53l1_parse_tree(&i2c_data->client->dev, i2c_data);
@ -921,6 +923,10 @@ static void memory_release(struct kref *kref)
struct i2c_data *data = container_of(kref, struct i2c_data, ref);
vl53l1_dbgmsg("Enter\n");
mutex_lock(&data->dma_data.lock);
if (data->dma_data.len > 0 && data->dma_data.data)
kfree(data->dma_data.data);
mutex_unlock(&data->dma_data.lock);
kfree(data->vl53l1_data);
kfree(data);
vl53l1_dbgmsg("End\n");