From patchwork Thu Jul 7 17:17:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Franklin Cooper X-Patchwork-Id: 9219275 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9B05860467 for ; Thu, 7 Jul 2016 17:18:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 88F0228405 for ; Thu, 7 Jul 2016 17:18:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7D29528407; Thu, 7 Jul 2016 17:18:35 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 62DE428405 for ; Thu, 7 Jul 2016 17:18:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753431AbcGGRSQ (ORCPT ); Thu, 7 Jul 2016 13:18:16 -0400 Received: from mail-oi0-f68.google.com ([209.85.218.68]:36027 "EHLO mail-oi0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932230AbcGGRSA (ORCPT ); Thu, 7 Jul 2016 13:18:00 -0400 Received: by mail-oi0-f68.google.com with SMTP id j134so2686288oib.3; Thu, 07 Jul 2016 10:17:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ZmbrlgY+GPrewRWOY5aFmu1GQ2DnoybtAbUINlNLsaU=; b=VapkFfJJG0gxaZ9tyd+yA6n6/Qtwoh106TySzoaNKPoCM9PwHkKm67CQMvlmC3aXTE E7rgx9sx1gqbS0IS/aqMLfiEn7AO6DPA9PGNMbThcbsgEWpoEnlJLKC+XrIswPTSGYg8 s6oAoZCxPr2DR31S59buG9e0W6u/WRGIF5QvmR5uCHoQTW3zu5BdXun+OvwpsBy2OXLW BvtDn8FgF62nDF1l9yHqmmRhehxXmxmjfmL/+84kRG30BQm8Dndy+6y4tZrnanFke9Cy conMWyaXlp1+1x61XvncJJVJ1DZBdwj7NyadEvrGaYuuwqACZ9+bKDPLfNPsFNytvvYc r9ew== X-Gm-Message-State: ALyK8tIVrPI+BY2bbWcwbm8XnI1B1cFhldrzuwCiTOxGhtf+9MT7JMmmqFKGrDw2IrpJqA== X-Received: by 10.202.229.206 with SMTP id c197mr741500oih.161.1467911878936; Thu, 07 Jul 2016 10:17:58 -0700 (PDT) Received: from beast-server.fios-router.home ([108.19.207.229]) by smtp.gmail.com with ESMTPSA id 187sm12288245oid.20.2016.07.07.10.17.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 Jul 2016 10:17:58 -0700 (PDT) From: Franklin S Cooper Jr To: tony@atomide.com, robh+dt@kernel.org, broonie@kernel.org, linux-omap@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, andy.shevchenko@gmail.com, robert.jarzmik@free.fr, nsekhar@ti.com Cc: Franklin S Cooper Jr Subject: [RFC] [PATCH v3 3/4] spi: omap2-mcspi: Use the SPI framework to handle DMA mapping Date: Thu, 7 Jul 2016 12:17:50 -0500 Message-Id: <1467911871-4508-4-git-send-email-fcooper@ti.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1467911871-4508-1-git-send-email-fcooper@ti.com> References: <1467911871-4508-1-git-send-email-fcooper@ti.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Currently, the driver handles mapping buffers to be used by the DMA. However, there are times that the current mapping implementation will fail for certain buffers. Fortunately, the SPI framework can detect and map buffers so its usable by the DMA. Update the driver to utilize the SPI framework for buffer mapping instead. Also incorporate hooks that the framework uses to determine if the DMA can or can not be used. This will result in the original omap2_mcspi_transfer_one function being deleted and omap2_mcspi_work_one being renamed to omap2_mcspi_transfer_one. Previously transfer_one was only responsible for mapping and work_one handled the transfer. But now only transferring needs to be handled by the driver. Signed-off-by: Franklin S Cooper Jr --- v3 changes: Use sg_split rather than custom sg table clone function. drivers/spi/spi-omap2-mcspi.c | 132 ++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 76 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index c47f958..d5157b2 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -419,16 +419,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi, if (mcspi_dma->dma_tx) { struct dma_async_tx_descriptor *tx; - struct scatterlist sg; dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); - sg_init_table(&sg, 1); - sg_dma_address(&sg) = xfer->tx_dma; - sg_dma_len(&sg) = xfer->len; - - tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1, - DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl, + xfer->tx_sg.nents, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_tx_callback; tx->callback_param = spi; @@ -449,7 +446,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, { struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; - unsigned int count, dma_count; + unsigned int count, transfer_reduction = 0; + struct scatterlist *sg_out[2]; + int nb_sizes = 0, out_mapped_nents[2], ret, x; + size_t sizes[2]; u32 l; int elements = 0; int word_len, element_count; @@ -457,7 +457,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; - dma_count = xfer->len; /* * In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM @@ -465,7 +464,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, * normal mode. */ if (mcspi->fifo_depth == 0) - dma_count -= es; + transfer_reduction = es; word_len = cs->word_len; l = mcspi_cached_chconf0(spi); @@ -479,7 +478,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (mcspi_dma->dma_rx) { struct dma_async_tx_descriptor *tx; - struct scatterlist sg; dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); @@ -488,15 +486,38 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, * configured in turbo mode. */ if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) - dma_count -= es; + transfer_reduction += es; - sg_init_table(&sg, 1); - sg_dma_address(&sg) = xfer->rx_dma; - sg_dma_len(&sg) = dma_count; + if (transfer_reduction) { + /* Split sgl into two. The second sgl won't be used. */ + sizes[0] = count - transfer_reduction; + sizes[1] = transfer_reduction; + nb_sizes = 2; + } else { + /* + * Don't bother splitting the sgl. This essentially + * clones the original sgl. + */ + sizes[0] = count; + nb_sizes = 1; + } + + ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, + 0, nb_sizes, + sizes, + sg_out, out_mapped_nents, + GFP_KERNEL); - tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | - DMA_CTRL_ACK); + if (ret < 0) { + dev_err(&spi->dev, "sg_split failed\n"); + return 0; + } + + tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, + sg_out[0], + out_mapped_nents[0], + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_rx_callback; tx->callback_param = spi; @@ -510,8 +531,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, omap2_mcspi_set_dma_req(spi, 1, 1); wait_for_completion(&mcspi_dma->dma_rx_completion); - dma_unmap_single(mcspi->dev, xfer->rx_dma, count, - DMA_FROM_DEVICE); + + for (x = 0; x < nb_sizes; x++) + kfree(sg_out[x]); if (mcspi->fifo_depth > 0) return count; @@ -628,8 +650,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) if (tx != NULL) { wait_for_completion(&mcspi_dma->dma_tx_completion); - dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, - DMA_TO_DEVICE); if (mcspi->fifo_depth > 0) { irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; @@ -1087,8 +1107,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) gpio_free(spi->cs_gpio); } -static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, - struct spi_device *spi, struct spi_transfer *t) +static int omap2_mcspi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { /* We only enable one channel at a time -- the one whose message is @@ -1098,7 +1119,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, * chipselect with the FORCE bit ... CS != channel enable. */ - struct spi_master *master; + struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_cs *cs; struct omap2_mcspi_device_config *cd; @@ -1106,7 +1127,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, int status = 0; u32 chconf; - master = spi->master; + mcspi = spi_master_get_devdata(master); mcspi_dma = mcspi->dma_channels + spi->chip_select; cs = spi->controller_state; cd = spi->controller_data; @@ -1166,7 +1187,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, unsigned count; if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - (t->len >= DMA_MIN_BYTES)) + master->cur_msg_mapped && + master->can_dma(master, spi, t)) omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_enable(spi, 1); @@ -1177,7 +1199,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, + OMAP2_MCSPI_TX0); if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - (t->len >= DMA_MIN_BYTES)) + master->cur_msg_mapped && + master->can_dma(master, spi, t)) count = omap2_mcspi_txrx_dma(spi, t); else count = omap2_mcspi_txrx_pio(spi, t); @@ -1246,55 +1269,11 @@ static int omap2_mcspi_prepare_message(struct spi_master *master, return 0; } -static int omap2_mcspi_transfer_one(struct spi_master *master, - struct spi_device *spi, struct spi_transfer *t) +static bool omap2_mcspi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) { - struct omap2_mcspi *mcspi; - struct omap2_mcspi_dma *mcspi_dma; - const void *tx_buf = t->tx_buf; - void *rx_buf = t->rx_buf; - unsigned len = t->len; - - mcspi = spi_master_get_devdata(master); - mcspi_dma = mcspi->dma_channels + spi->chip_select; - - if ((len && !(rx_buf || tx_buf))) { - dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", - t->speed_hz, - len, - tx_buf ? "tx" : "", - rx_buf ? "rx" : "", - t->bits_per_word); - return -EINVAL; - } - - if (len < DMA_MIN_BYTES) - goto skip_dma_map; - - if (mcspi_dma->dma_tx && tx_buf != NULL) { - t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf, - len, DMA_TO_DEVICE); - if (dma_mapping_error(mcspi->dev, t->tx_dma)) { - dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", - 'T', len); - return -EINVAL; - } - } - if (mcspi_dma->dma_rx && rx_buf != NULL) { - t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len, - DMA_FROM_DEVICE); - if (dma_mapping_error(mcspi->dev, t->rx_dma)) { - dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", - 'R', len); - if (tx_buf != NULL) - dma_unmap_single(mcspi->dev, t->tx_dma, - len, DMA_TO_DEVICE); - return -EINVAL; - } - } - -skip_dma_map: - return omap2_mcspi_work_one(mcspi, spi, t); + return (xfer->len >= DMA_MIN_BYTES); } static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) @@ -1374,6 +1353,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->setup = omap2_mcspi_setup; master->auto_runtime_pm = true; master->prepare_message = omap2_mcspi_prepare_message; + master->can_dma = omap2_mcspi_can_dma; master->transfer_one = omap2_mcspi_transfer_one; master->set_cs = omap2_mcspi_set_cs; master->cleanup = omap2_mcspi_cleanup;