mtd: gpmi: add sanity check when mapping DMA for read_buf/write_buf
authorHuang Shijie <shijie8@gmail.com>
Wed, 18 Dec 2013 15:41:00 +0000 (23:41 +0800)
committerBrian Norris <computersforpeace@gmail.com>
Tue, 28 Jan 2014 05:55:03 +0000 (21:55 -0800)
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>
drivers/mtd/nand/gpmi-nand/gpmi-nand.c

index d1d13d8..ca6369f 100644 (file)
@@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
        struct scatterlist *sgl = &this->data_sgl;
        int ret;
 
-       this->direct_dma_map_ok = true;
-
        /* first try to map the upper buffer directly */
-       sg_init_one(sgl, this->upper_buf, this->upper_len);
-       ret = dma_map_sg(this->dev, sgl, 1, dr);
-       if (ret == 0) {
-               /* We have to use our own DMA buffer. */
-               sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE);
-
-               if (dr == DMA_TO_DEVICE)
-                       memcpy(this->data_buffer_dma, this->upper_buf,
-                               this->upper_len);
-
+       if (virt_addr_valid(this->upper_buf) &&
+               !object_is_on_stack(this->upper_buf)) {
+               sg_init_one(sgl, this->upper_buf, this->upper_len);
                ret = dma_map_sg(this->dev, sgl, 1, dr);
                if (ret == 0)
-                       dev_err(this->dev, "DMA mapping failed.\n");
+                       goto map_fail;
 
-               this->direct_dma_map_ok = false;
+               this->direct_dma_map_ok = true;
+               return;
        }
+
+map_fail:
+       /* We have to use our own DMA buffer. */
+       sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
+
+       if (dr == DMA_TO_DEVICE)
+               memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
+
+       dma_map_sg(this->dev, sgl, 1, dr);
+
+       this->direct_dma_map_ok = false;
 }
 
 /* This will be called after the DMA operation is finished. */