From patchwork Mon Sep 24 09:18:35 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bastian Hecht X-Patchwork-Id: 186338 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (unknown [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 6980B2C0081 for ; Mon, 24 Sep 2012 19:19:39 +1000 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TG4oW-000062-1r; Mon, 24 Sep 2012 09:18:52 +0000 Received: from mail-wi0-f171.google.com ([209.85.212.171]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TG4oO-0008VU-I8 for linux-mtd@lists.infradead.org; Mon, 24 Sep 2012 09:18:45 +0000 Received: by wibhq4 with SMTP id hq4so3345529wib.0 for ; Mon, 24 Sep 2012 02:18:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=bSi1a5XuU6hUCA5UOjl8ZMiheyXO49q1Kzm1H8EdwNQ=; b=eQMtPWKj/h/C+CDQHuBTkD0by2KUc8+JSqZQQRhOWfSXPxIGUKKysKYiOjiAJBH5hI 4kedA07xKsxZp6mEyOxzhrqQBe0XEP0entCth6m3BQwowkAPPE1O1NGwn76DVfm6RiLv bVczEZ8lzFQtGRoLJTsqkp34xWSLUOAJFVGGPGPxFzzK7qSFV8DCpsMGymb8tB78zLuB GxeJhZSmjlC0IclJ3O/P7NkKwqL7Qlia29FgQD5ydNc81cEMfXJ1tjBlGQ03qm89IooH IpZaJpqgbOBMZvGvAIpusTHXhB6a4An1fA/I9hgUTFhyPa56ReeMQDcUVHjWiPdAuSm4 UOCA== Received: by 10.217.1.136 with SMTP id n8mr6623268wes.10.1348478323408; Mon, 24 Sep 2012 02:18:43 -0700 (PDT) Received: from localhost.localdomain (p4FD261FA.dip.t-dialin.net. [79.210.97.250]) by mx.google.com with ESMTPS id ga2sm3791775wib.2.2012.09.24.02.18.41 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 24 Sep 2012 02:18:42 -0700 (PDT) From: Bastian Hecht To: linux-mtd@lists.infradead.org Subject: [PATCH v2 2/2] mtd: sh_flctl: Use DMA for data fifo FLTDFIFO when available Date: Mon, 24 Sep 2012 11:18:35 +0200 Message-Id: <1348478315-10789-2-git-send-email-hechtb@gmail.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1348478315-10789-1-git-send-email-hechtb@gmail.com> References: <1348478315-10789-1-git-send-email-hechtb@gmail.com> X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.212.171 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (hechtb[at]googlemail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Magnus Damm , Guennadi Liakhovetski , linux-sh@vger.kernel.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Map and unmap DMA buffers, trigger the DMA and wait for the completion. On failure we fallback to PIO mode. Signed-off-by: Bastian Hecht --- log v2: dropped a forward declaration drivers/mtd/nand/sh_flctl.c | 97 +++++++++++++++++++++++++++++++++++++++++- include/linux/mtd/sh_flctl.h | 1 + 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 9659483..0d90af8 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -106,6 +108,13 @@ static void wait_completion(struct sh_flctl *flctl) writeb(0x0, FLTRCR(flctl)); } +static void flctl_dma_complete(void *param) +{ + struct sh_flctl *flctl = param; + + complete(&flctl->dma_complete); +} + static void flctl_release_dma(struct sh_flctl *flctl) { if (flctl->chan_fifo0_rx) { @@ -331,6 +340,69 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl) timeout_error(flctl, __func__); } +static void flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, + int len, enum dma_data_direction dir) +{ + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *chan; + enum dma_transfer_direction tr_dir; + dma_addr_t dma_addr; + dma_cookie_t cookie = -EINVAL; + uint32_t reg; + int ret; + + if (dir == DMA_FROM_DEVICE) { + chan = flctl->chan_fifo0_rx; + tr_dir = DMA_DEV_TO_MEM; + } else { + chan = flctl->chan_fifo0_tx; + tr_dir = DMA_MEM_TO_DEV; + } + + dma_addr = dma_map_single(chan->device->dev, buf, len, dir); + + if (dma_addr) + desc = dmaengine_prep_slave_single(chan, dma_addr, len, + tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + + if (desc) { + reg = readl(FLINTDMACR(flctl)); + reg |= DREQ0EN; + writel(reg, FLINTDMACR(flctl)); + + desc->callback = flctl_dma_complete; + desc->callback_param = flctl; + cookie = dmaengine_submit(desc); + + dma_async_issue_pending(chan); + } + + if (!desc) { + /* DMA failed, fall back to PIO */ + flctl_release_dma(flctl); + dev_warn(&flctl->pdev->dev, + "DMA failed, falling back to PIO\n"); + goto out; + } + + ret = + wait_for_completion_timeout(&flctl->dma_complete, + msecs_to_jiffies(3000)); + + if (ret <= 0) { + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n"); + } + +out: + reg = readl(FLINTDMACR(flctl)); + reg &= ~DREQ0EN; + writel(reg, FLINTDMACR(flctl)); + + dma_unmap_single(chan->device->dev, dma_addr, len, dir); + init_completion(&flctl->dma_complete); +} + static void read_datareg(struct sh_flctl *flctl, int offset) { unsigned long data; @@ -349,6 +421,16 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) len_4align = (rlen + 3) / 4; + /* initiate DMA transfer */ + if (flctl->chan_fifo0_rx && rlen >= 32) { + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM); + for (i = 0; i < len_4align; i++) + buf[i] = be32_to_cpu(buf[i]); + + return; + } + + /* do polling transfer */ for (i = 0; i < len_4align; i++) { wait_rfifo_ready(flctl); buf[i] = readl(FLDTFIFO(flctl)); @@ -378,13 +460,24 @@ static enum flctl_ecc_res_t read_ecfiforeg static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) { int i, len_4align; - unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; + unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; void *fifo_addr = (void *)FLDTFIFO(flctl); len_4align = (rlen + 3) / 4; + + /* initiate DMA transfer */ + if (flctl->chan_fifo0_tx && rlen >= 32) { + for (i = 0; i < len_4align; i++) + buf[i] = cpu_to_be32(buf[i]); + + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV); + return; + } + + /* do polling transfer */ for (i = 0; i < len_4align; i++) { wait_wfifo_ready(flctl); - writel(cpu_to_be32(data[i]), fifo_addr); + writel(cpu_to_be32(buf[i]), fifo_addr); } } diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 20d3f48..d55ec25 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -109,6 +109,7 @@ #define ESTERINTE (0x1 << 24) /* ECC error interrupt enable */ #define AC1CLR (0x1 << 19) /* ECC FIFO clear */ #define AC0CLR (0x1 << 18) /* Data FIFO clear */ +#define DREQ0EN (0x1 << 16) /* FLDTFIFODMA Request Enable */ #define ECERB (0x1 << 9) /* ECC error */ #define STERB (0x1 << 8) /* Status error */ #define STERINTE (0x1 << 4) /* Status error enable */