[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