mtd: OneNAND: S5PC110: Fix wrong DMA handling when HIGHMEM
authorKyungmin Park <kyungmin.park@samsung.com>
Tue, 28 Sep 2010 10:27:10 +0000 (19:27 +0900)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sun, 24 Oct 2010 23:51:33 +0000 (00:51 +0100)
When use HIGHMEM, dma_map_single doesn't get the proper DMA address.
So use the dma_map_page in this case.

Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
drivers/mtd/onenand/samsung.c

index 285085a..afdb4c5 100644 (file)
@@ -582,7 +582,8 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
        void __iomem *p;
        void *buf = (void *) buffer;
        dma_addr_t dma_src, dma_dst;
-       int err;
+       int err, page_dma = 0;
+       struct device *dev = &onenand->pdev->dev;
 
        p = this->base + area;
        if (ONENAND_CURRENT_BUFFERRAM(this)) {
@@ -606,21 +607,27 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
                page = vmalloc_to_page(buf);
                if (!page)
                        goto normal;
-               buf = page_address(page) + ((size_t) buf & ~PAGE_MASK);
-       }
 
-       /* DMA routine */
-       dma_src = onenand->phys_base + (p - this->base);
-       dma_dst = dma_map_single(&onenand->pdev->dev,
-                       buf, count, DMA_FROM_DEVICE);
-       if (dma_mapping_error(&onenand->pdev->dev, dma_dst)) {
-               dev_err(&onenand->pdev->dev,
-                       "Couldn't map a %d byte buffer for DMA\n", count);
+               page_dma = 1;
+               /* DMA routine */
+               dma_src = onenand->phys_base + (p - this->base);
+               dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE);
+       } else {
+               /* DMA routine */
+               dma_src = onenand->phys_base + (p - this->base);
+               dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
+       }
+       if (dma_mapping_error(dev, dma_dst)) {
+               dev_err(dev, "Couldn't map a %d byte buffer for DMA\n", count);
                goto normal;
        }
        err = s5pc110_dma_ops((void *) dma_dst, (void *) dma_src,
                        count, S5PC110_DMA_DIR_READ);
-       dma_unmap_single(&onenand->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+       if (page_dma)
+               dma_unmap_page(dev, dma_dst, count, DMA_FROM_DEVICE);
+       else
+               dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE);
 
        if (!err)
                return 0;