Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6732cfd4 authored by Ladislav Michl's avatar Ladislav Michl Committed by Boris Brezillon
Browse files

mtd: onenand: omap2: Disable DMA for HIGHMEM buffers



dma_map_single does not work for vmalloc-ed buffers,
so disable DMA in this case.

Signed-off-by: default avatarLadislav Michl <ladis@linux-mips.org>
Reported-by: default avatar"H. Nikolaus Schaller" <hns@goldelico.com>
Tested-by: default avatar"H. Nikolaus Schaller" <hns@goldelico.com>
Reviewed-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@bootlin.com>
parent 6da6c0db
Loading
Loading
Loading
Loading
+38 −67
Original line number Diff line number Diff line
@@ -375,31 +375,21 @@ static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
{
	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
	struct onenand_chip *this = mtd->priv;
	dma_addr_t dma_src, dma_dst;
	int bram_offset;
	struct device *dev = &c->pdev->dev;
	void *buf = (void *)buffer;
	dma_addr_t dma_src, dma_dst;
	int bram_offset, err;
	size_t xtra;
	int ret;

	bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
	if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
		goto out_copy;

	/* panic_write() may be in an interrupt context */
	if (in_interrupt() || oops_in_progress)
		goto out_copy;

	if (buf >= high_memory) {
		struct page *p1;

		if (((size_t)buf & PAGE_MASK) !=
		    ((size_t)(buf + count - 1) & PAGE_MASK))
			goto out_copy;
		p1 = vmalloc_to_page(buf);
		if (!p1)
	/*
	 * If the buffer address is not DMA-able, len is not long enough to make
	 * DMA transfers profitable or panic_write() may be in an interrupt
	 * context fallback to PIO mode.
	 */
	if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 ||
	    count < 384 || in_interrupt() || oops_in_progress )
		goto out_copy;
		buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
	}

	xtra = count & 3;
	if (xtra) {
@@ -407,25 +397,21 @@ static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
		memcpy(buf + count, this->base + bram_offset + count, xtra);
	}

	dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE);
	dma_src = c->phys_base + bram_offset;
	dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE);
	if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
		dev_err(&c->pdev->dev,
			"Couldn't DMA map a %d byte buffer\n",
			count);
		goto out_copy;
	}

	ret = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count);
	dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);

	if (ret) {
		dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
	if (dma_mapping_error(dev, dma_dst)) {
		dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count);
		goto out_copy;
	}

	err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count);
	dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE);
	if (!err)
		return 0;

	dev_err(dev, "timeout waiting for DMA\n");

out_copy:
	memcpy(buf, this->base + bram_offset, count);
	return 0;
@@ -437,50 +423,35 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
{
	struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
	struct onenand_chip *this = mtd->priv;
	dma_addr_t dma_src, dma_dst;
	int bram_offset;
	struct device *dev = &c->pdev->dev;
	void *buf = (void *)buffer;
	int ret;
	dma_addr_t dma_src, dma_dst;
	int bram_offset, err;

	bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
	if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
		goto out_copy;

	/* panic_write() may be in an interrupt context */
	if (in_interrupt() || oops_in_progress)
		goto out_copy;

	if (buf >= high_memory) {
		struct page *p1;

		if (((size_t)buf & PAGE_MASK) !=
		    ((size_t)(buf + count - 1) & PAGE_MASK))
			goto out_copy;
		p1 = vmalloc_to_page(buf);
		if (!p1)
	/*
	 * If the buffer address is not DMA-able, len is not long enough to make
	 * DMA transfers profitable or panic_write() may be in an interrupt
	 * context fallback to PIO mode.
	 */
	if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 ||
	    count < 384 || in_interrupt() || oops_in_progress )
		goto out_copy;
		buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
	}

	dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE);
	dma_src = dma_map_single(dev, buf, count, DMA_TO_DEVICE);
	dma_dst = c->phys_base + bram_offset;
	if (dma_mapping_error(&c->pdev->dev, dma_src)) {
		dev_err(&c->pdev->dev,
			"Couldn't DMA map a %d byte buffer\n",
			count);
		return -1;
	}

	ret = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count);
	dma_unmap_single(&c->pdev->dev, dma_src, count, DMA_TO_DEVICE);

	if (ret) {
		dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
	if (dma_mapping_error(dev, dma_src)) {
		dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count);
		goto out_copy;
	}

	err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count);
	dma_unmap_page(dev, dma_src, count, DMA_TO_DEVICE);
	if (!err)
		return 0;

	dev_err(dev, "timeout waiting for DMA\n");

out_copy:
	memcpy(this->base + bram_offset, buf, count);
	return 0;