diff options
author | Huang Shijie <shijie8@gmail.com> | 2013-12-18 10:41:00 -0500 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-01-28 00:55:03 -0500 |
commit | 0ff76a920e3558307567b45aa0a91fb914924bfc (patch) | |
tree | de9fcf55103af0f753dda69599989c3b63758112 /drivers/mtd | |
parent | 06f216c83c25adadc231469d51ab133afdfe110a (diff) |
mtd: gpmi: add sanity check when mapping DMA for read_buf/write_buf
The buffer pointer passed from the upper layer may points to
a buffer in the stack or a buffer allocated by vmalloc, and etc..
This patch adds more sanity check to this buffer.
After this patch, if we meet a buffer which is allocated by vmalloc or
a buffer in the stack, we will use our own DMA buffer @data_buffer_dma
to do the DMA operations. If the buffer is not the cases above, we will
map it for DMA operations directly.
Signed-off-by: Huang Shijie <shijie8@gmail.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d1d13d86b7e0..ca6369fe91ff 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
@@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) | |||
367 | struct scatterlist *sgl = &this->data_sgl; | 367 | struct scatterlist *sgl = &this->data_sgl; |
368 | int ret; | 368 | int ret; |
369 | 369 | ||
370 | this->direct_dma_map_ok = true; | ||
371 | |||
372 | /* first try to map the upper buffer directly */ | 370 | /* first try to map the upper buffer directly */ |
373 | sg_init_one(sgl, this->upper_buf, this->upper_len); | 371 | if (virt_addr_valid(this->upper_buf) && |
374 | ret = dma_map_sg(this->dev, sgl, 1, dr); | 372 | !object_is_on_stack(this->upper_buf)) { |
375 | if (ret == 0) { | 373 | sg_init_one(sgl, this->upper_buf, this->upper_len); |
376 | /* We have to use our own DMA buffer. */ | ||
377 | sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); | ||
378 | |||
379 | if (dr == DMA_TO_DEVICE) | ||
380 | memcpy(this->data_buffer_dma, this->upper_buf, | ||
381 | this->upper_len); | ||
382 | |||
383 | ret = dma_map_sg(this->dev, sgl, 1, dr); | 374 | ret = dma_map_sg(this->dev, sgl, 1, dr); |
384 | if (ret == 0) | 375 | if (ret == 0) |
385 | dev_err(this->dev, "DMA mapping failed.\n"); | 376 | goto map_fail; |
386 | 377 | ||
387 | this->direct_dma_map_ok = false; | 378 | this->direct_dma_map_ok = true; |
379 | return; | ||
388 | } | 380 | } |
381 | |||
382 | map_fail: | ||
383 | /* We have to use our own DMA buffer. */ | ||
384 | sg_init_one(sgl, this->data_buffer_dma, this->upper_len); | ||
385 | |||
386 | if (dr == DMA_TO_DEVICE) | ||
387 | memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len); | ||
388 | |||
389 | dma_map_sg(this->dev, sgl, 1, dr); | ||
390 | |||
391 | this->direct_dma_map_ok = false; | ||
389 | } | 392 | } |
390 | 393 | ||
391 | /* This will be called after the DMA operation is finished. */ | 394 | /* This will be called after the DMA operation is finished. */ |