Received: by 10.192.165.148 with SMTP id m20csp475541imm; Wed, 2 May 2018 03:42:43 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqk0MQCJpnmBkdwMykSLciv8nrmjQj0fjlHSyY39A3ILnHocBUX7M0v3+j/4C3YgLu2g4Z+ X-Received: by 2002:a17:902:2947:: with SMTP id g65-v6mr19278979plb.346.1525257763827; Wed, 02 May 2018 03:42:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525257763; cv=none; d=google.com; s=arc-20160816; b=StU3dWuAztGSRaQGXrSbR0FGy5SIDjnjjxAekLJdEjFqwhfTky3Ksm1RpndUevQHW1 bAvUoyVmLocc/nK8K/z3172wb6s4201tmj596jy4/89Be1iW51Gzg8OJJPL07+XBMwp/ rxvF6ja939LfspSYIQn/lrtTMKOWyLKpC1QL2KDij3Gwb2IitO9EOSu4Dj0giXrKcwHN Cjna3oMbulpgFkbhk6wf8k4PrpYIIFDmi0oPs6g3n0B+XzbVXhBH9APXBsDJxJlAwTJr KWieLpnLC0E84cnO59G5oNG7cTlnvH5JgRZ+/7goZn2eafXVplTzih4gmmGKWJ2TQgxf oi2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:content-disposition :mime-version:message-id:subject:cc:to:from:date :arc-authentication-results; bh=3wZAXhNisAjQDpNThP5seKaSIoRb9ddFjE3YUCSB33o=; b=ZHkQPDhvKkJIzM6XoPBocqrZu4WVA4W2GstyP6Ad1ay2s+Fy7Ev8+mmVGwau4sqCBi sCwy5FE1+XecAaPiCuLWo4wj3VGdE0jlQCZUNENfy/aZcdh8yFj6SVui9TW4tdayDkUM QYh6w+fRl0WNYLBKRskGb4D9oNsIJRCvtTm3GlYsRvHS3bDGjDu7XROmQcjw3Bw16wgh 1YJQ3Bd4Z8j4pgKyuDYkdAn/2J0bAaoNWV+9MLP5qW/puWS88yUg+tsV1vFbd7JEZzDS VztPzPoXIoOl50bxIuG5AVTvkafaV7fn3ix5+u6SZ6//hy1fHZ5nXIoMUpPDgQqj40xO kESQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e9-v6si11467874plt.209.2018.05.02.03.42.29; Wed, 02 May 2018 03:42:43 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751257AbeEBKlg (ORCPT + 99 others); Wed, 2 May 2018 06:41:36 -0400 Received: from eddie.linux-mips.org ([148.251.95.138]:33410 "EHLO cvs.linux-mips.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750883AbeEBKlf (ORCPT ); Wed, 2 May 2018 06:41:35 -0400 Received: (from localhost user: 'ladis' uid#1021 fake: STDIN (ladis@eddie.linux-mips.org)) by eddie.linux-mips.org id S23991534AbeEBKldkQxAh (ORCPT ); Wed, 2 May 2018 12:41:33 +0200 Date: Wed, 2 May 2018 12:41:32 +0200 From: Ladislav Michl To: Boris Brezillon Cc: linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Peter Ujfalusi , Roger Quadros , Aaro Koskinen , Tony Lindgren , "H. Nikolaus Schaller" , Andreas Kemnade Subject: [PATCH v3] mtd: onenand: omap2: Disable DMA for HIGHMEM buffers Message-ID: <20180502104132.GA12979@lenoch> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.9.5 (2018-04-13) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org dma_map_single does not work for vmalloc-ed buffers, so disable DMA in this case. Signed-off-by: Ladislav Michl Reported-by: "H. Nikolaus Schaller" Tested-by: "H. Nikolaus Schaller" --- Changes: -v2: Added Tested-by tag, based on v4.17-rc1 (no change in patch itself) -v3: Reworded commit log drivers/mtd/nand/onenand/omap2.c | 105 +++++++++++-------------------- 1 file changed, 38 insertions(+), 67 deletions(-) diff --git a/drivers/mtd/nand/onenand/omap2.c b/drivers/mtd/nand/onenand/omap2.c index 9c159f0dd9a6..321137158ff3 100644 --- a/drivers/mtd/nand/onenand/omap2.c +++ b/drivers/mtd/nand/onenand/omap2.c @@ -375,56 +375,42 @@ 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) + /* + * 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; - 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) - goto out_copy; - buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); - } - xtra = count & 3; if (xtra) { count -= xtra; 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; } - return 0; + 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); @@ -437,49 +423,34 @@ 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) + /* + * 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; - 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) - 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; } - return 0; + 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); -- 2.17.0