[PATCH] mtd: OneNAND: samsung: Write DMA support
Kyungmin Park
kmpark at infradead.org
Wed Jun 8 06:18:04 EDT 2011
From: Kyungmin Park <kyungmin.park at samsung.com>
Implement the write DMA feature. It can reduce the CPU usage when write.
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index 3306b5b..f24cb6f 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -712,6 +712,74 @@ normal:
return 0;
}
+static int s5pc110_write_bufferram(struct mtd_info *mtd, int area,
+ const unsigned char *buffer, int offset, size_t count)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct device *dev = &onenand->pdev->dev;
+ void __iomem *p;
+ void *buf = (void *) buffer;
+ dma_addr_t dma_src, dma_dst;
+ int err, ofs, page_dma = 0;
+
+ p = this->base + area;
+ if (ONENAND_CURRENT_BUFFERRAM(this)) {
+ if (area == ONENAND_DATARAM)
+ p += this->writesize;
+ else
+ p += mtd->oobsize;
+ }
+
+ if (count != mtd->writesize || offset & 3 || (size_t) buf & 3)
+ goto normal;
+
+ /* Handle vmalloc address */
+ if (buf >= high_memory) {
+ struct page *page;
+
+ if (((size_t) buf & PAGE_MASK) !=
+ ((size_t) (buf + count - 1) & PAGE_MASK))
+ goto normal;
+
+ page = vmalloc_to_page(buf);
+ if (unlikely(!page))
+ goto normal;
+
+ /* Page offset */
+ ofs = ((size_t) buf & ~PAGE_MASK);
+ page_dma = 1;
+
+ /* DMA routine */
+ dma_src = dma_map_page(dev, page, ofs, count, DMA_TO_DEVICE);
+ dma_dst = onenand->phys_base + (p - this->base);
+ } else {
+ /* DMA routine */
+ dma_src = dma_map_single(dev, buf, count, DMA_TO_DEVICE);
+ dma_dst = onenand->phys_base + (p - this->base);
+ }
+
+ if (dma_mapping_error(dev, dma_src)) {
+ 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_WRITE);
+
+ if (page_dma)
+ dma_unmap_page(dev, dma_src, count, DMA_TO_DEVICE);
+ else
+ dma_unmap_single(dev, dma_src, count, DMA_TO_DEVICE);
+
+ if (!err)
+ return 0;
+
+normal:
+ memcpy(p + offset, buffer, count);
+
+ return 0;
+}
+
static int s5pc110_chip_probe(struct mtd_info *mtd)
{
/* Now just return 0 */
@@ -844,6 +912,7 @@ static void s3c_onenand_setup(struct mtd_info *mtd)
} else if (onenand->type == TYPE_S5PC110) {
/* Use generic onenand functions */
this->read_bufferram = s5pc110_read_bufferram;
+ this->write_bufferram = s5pc110_write_bufferram;
this->chip_probe = s5pc110_chip_probe;
return;
} else {
More information about the linux-mtd
mailing list