* [PATCH 1/2] spi: rspi: Fix leaking of unused DMA descriptors
@ 2014-07-11 16:06 Geert Uytterhoeven
2014-07-11 16:06 ` [PATCH 2/2] spi: sh-msiof: " Geert Uytterhoeven
2014-07-14 18:58 ` [PATCH 1/2] spi: rspi: " Mark Brown
0 siblings, 2 replies; 5+ messages in thread
From: Geert Uytterhoeven @ 2014-07-11 16:06 UTC (permalink / raw)
To: Mark Brown
Cc: Laurent Pinchart, linux-spi, dmaengine, linux-sh, linux-kernel,
Geert Uytterhoeven
If dmaengine_prep_slave_sg() or dmaengine_submit() fail, we may leak
unused DMA descriptors.
As per Documentation/dmaengine.txt, once a DMA descriptor has been
obtained, it must be submitted. Hence:
- First prepare and submit all DMA descriptors,
- Prepare the SPI controller for DMA,
- Start DMA by calling dma_async_issue_pending(),
- Make sure to call dmaengine_terminate_all() on all descriptors that
haven't completed.
Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/spi/spi-rspi.c | 94 +++++++++++++++++++++++++++++++-------------------
1 file changed, 58 insertions(+), 36 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index c850dfdfa9e3..ad87a98f8f68 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -472,25 +472,52 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
dma_cookie_t cookie;
int ret;
- if (tx) {
- desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
- tx->sgl, tx->nents, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_tx)
- goto no_dma;
-
- irq_mask |= SPCR_SPTIE;
- }
+ /* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx,
rx->sgl, rx->nents, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_rx)
- goto no_dma;
+ if (!desc_rx) {
+ ret = -EAGAIN;
+ goto no_dma_rx;
+ }
+
+ desc_rx->callback = rspi_dma_complete;
+ desc_rx->callback_param = rspi;
+ cookie = dmaengine_submit(desc_rx);
+ if (dma_submit_error(cookie)) {
+ ret = cookie;
+ goto no_dma_rx;
+ }
irq_mask |= SPCR_SPRIE;
}
+ if (tx) {
+ desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
+ tx->sgl, tx->nents, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx) {
+ ret = -EAGAIN;
+ goto no_dma_tx;
+ }
+
+ if (rx) {
+ /* No callback */
+ desc_tx->callback = NULL;
+ } else {
+ desc_tx->callback = rspi_dma_complete;
+ desc_tx->callback_param = rspi;
+ }
+ cookie = dmaengine_submit(desc_tx);
+ if (dma_submit_error(cookie)) {
+ ret = cookie;
+ goto no_dma_tx;
+ }
+
+ irq_mask |= SPCR_SPTIE;
+ }
+
/*
* DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
@@ -503,34 +530,24 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
rspi_enable_irq(rspi, irq_mask);
rspi->dma_callbacked = 0;
- if (rx) {
- desc_rx->callback = rspi_dma_complete;
- desc_rx->callback_param = rspi;
- cookie = dmaengine_submit(desc_rx);
- if (dma_submit_error(cookie))
- return cookie;
+ /* Now start DMA */
+ if (rx)
dma_async_issue_pending(rspi->master->dma_rx);
- }
- if (tx) {
- if (rx) {
- /* No callback */
- desc_tx->callback = NULL;
- } else {
- desc_tx->callback = rspi_dma_complete;
- desc_tx->callback_param = rspi;
- }
- cookie = dmaengine_submit(desc_tx);
- if (dma_submit_error(cookie))
- return cookie;
+ if (tx)
dma_async_issue_pending(rspi->master->dma_tx);
- }
ret = wait_event_interruptible_timeout(rspi->wait,
rspi->dma_callbacked, HZ);
if (ret > 0 && rspi->dma_callbacked)
ret = 0;
- else if (!ret)
+ else if (!ret) {
+ dev_err(&rspi->master->dev, "DMA timeout\n");
ret = -ETIMEDOUT;
+ if (tx)
+ dmaengine_terminate_all(rspi->master->dma_tx);
+ if (rx)
+ dmaengine_terminate_all(rspi->master->dma_rx);
+ }
rspi_disable_irq(rspi, irq_mask);
@@ -541,11 +558,16 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
return ret;
-no_dma:
- pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
- dev_driver_string(&rspi->master->dev),
- dev_name(&rspi->master->dev));
- return -EAGAIN;
+no_dma_tx:
+ if (rx)
+ dmaengine_terminate_all(rspi->master->dma_rx);
+no_dma_rx:
+ if (ret == -EAGAIN) {
+ pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
+ dev_driver_string(&rspi->master->dev),
+ dev_name(&rspi->master->dev));
+ }
+ return ret;
}
static void rspi_receive_init(const struct rspi_data *rspi)
--
1.9.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 2/2] spi: sh-msiof: Fix leaking of unused DMA descriptors 2014-07-11 16:06 [PATCH 1/2] spi: rspi: Fix leaking of unused DMA descriptors Geert Uytterhoeven @ 2014-07-11 16:06 ` Geert Uytterhoeven 2014-07-14 18:59 ` Mark Brown 2014-07-14 18:58 ` [PATCH 1/2] spi: rspi: " Mark Brown 1 sibling, 1 reply; 5+ messages in thread From: Geert Uytterhoeven @ 2014-07-11 16:06 UTC (permalink / raw) To: Mark Brown Cc: Laurent Pinchart, linux-spi, dmaengine, linux-sh, linux-kernel, Geert Uytterhoeven If dmaengine_prep_slave_sg() or dmaengine_submit() fail, we may leak unused DMA descriptors. As per Documentation/dmaengine.txt, once a DMA descriptor has been obtained, it must be submitted. Hence: - First prepare and submit all DMA descriptors, - Prepare the SPI controller for DMA, - Start DMA by calling dma_async_issue_pending(), - Make sure to call dmaengine_terminate_all() on all descriptors that haven't completed. Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> --- drivers/spi/spi-sh-msiof.c | 71 +++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2a4354dcd661..887c2084130f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -636,48 +636,38 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, dma_cookie_t cookie; int ret; - if (tx) { - ier_bits |= IER_TDREQE | IER_TDMAE; - dma_sync_single_for_device(p->master->dma_tx->device->dev, - p->tx_dma_addr, len, DMA_TO_DEVICE); - desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, - p->tx_dma_addr, len, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_tx) - return -EAGAIN; - } - + /* First prepare and submit the DMA request(s), as this may fail */ if (rx) { ier_bits |= IER_RDREQE | IER_RDMAE; desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, p->rx_dma_addr, len, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_rx) - return -EAGAIN; - } - - /* 1 stage FIFO watermarks for DMA */ - sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); - - /* setup msiof transfer mode registers (32-bit words) */ - sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); - - sh_msiof_write(p, IER, ier_bits); - - reinit_completion(&p->done); + if (!desc_rx) { + ret = -EAGAIN; + goto no_dma_rx; + } - if (rx) { desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback_param = p; cookie = dmaengine_submit(desc_rx); if (dma_submit_error(cookie)) { ret = cookie; - goto stop_ier; + goto no_dma_rx; } - dma_async_issue_pending(p->master->dma_rx); } if (tx) { + ier_bits |= IER_TDREQE | IER_TDMAE; + dma_sync_single_for_device(p->master->dma_tx->device->dev, + p->tx_dma_addr, len, DMA_TO_DEVICE); + desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, + p->tx_dma_addr, len, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_tx) { + ret = -EAGAIN; + goto no_dma_tx; + } + if (rx) { /* No callback */ desc_tx->callback = NULL; @@ -688,15 +678,30 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, cookie = dmaengine_submit(desc_tx); if (dma_submit_error(cookie)) { ret = cookie; - goto stop_rx; + goto no_dma_tx; } - dma_async_issue_pending(p->master->dma_tx); } + /* 1 stage FIFO watermarks for DMA */ + sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); + + /* setup msiof transfer mode registers (32-bit words) */ + sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); + + sh_msiof_write(p, IER, ier_bits); + + reinit_completion(&p->done); + + /* Now start DMA */ + if (tx) + dma_async_issue_pending(p->master->dma_rx); + if (rx) + dma_async_issue_pending(p->master->dma_tx); + ret = sh_msiof_spi_start(p, rx); if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); - goto stop_tx; + goto stop_dma; } /* wait for tx fifo to be emptied / rx fifo to be filled */ @@ -726,14 +731,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx); -stop_tx: +stop_dma: if (tx) dmaengine_terminate_all(p->master->dma_tx); -stop_rx: +no_dma_tx: if (rx) dmaengine_terminate_all(p->master->dma_rx); -stop_ier: sh_msiof_write(p, IER, 0); +no_dma_rx: return ret; } -- 1.9.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] spi: sh-msiof: Fix leaking of unused DMA descriptors 2014-07-11 16:06 ` [PATCH 2/2] spi: sh-msiof: " Geert Uytterhoeven @ 2014-07-14 18:59 ` Mark Brown 0 siblings, 0 replies; 5+ messages in thread From: Mark Brown @ 2014-07-14 18:59 UTC (permalink / raw) To: Geert Uytterhoeven Cc: Laurent Pinchart, linux-spi, dmaengine, linux-sh, linux-kernel [-- Attachment #1: Type: text/plain, Size: 204 bytes --] On Fri, Jul 11, 2014 at 06:06:42PM +0200, Geert Uytterhoeven wrote: > If dmaengine_prep_slave_sg() or dmaengine_submit() fail, we may leak > unused DMA descriptors. Same here, this doesn't apply either. [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] spi: rspi: Fix leaking of unused DMA descriptors 2014-07-11 16:06 [PATCH 1/2] spi: rspi: Fix leaking of unused DMA descriptors Geert Uytterhoeven 2014-07-11 16:06 ` [PATCH 2/2] spi: sh-msiof: " Geert Uytterhoeven @ 2014-07-14 18:58 ` Mark Brown 2014-08-05 14:34 ` Geert Uytterhoeven 1 sibling, 1 reply; 5+ messages in thread From: Mark Brown @ 2014-07-14 18:58 UTC (permalink / raw) To: Geert Uytterhoeven Cc: Laurent Pinchart, linux-spi, dmaengine, linux-sh, linux-kernel [-- Attachment #1: Type: text/plain, Size: 365 bytes --] On Fri, Jul 11, 2014 at 06:06:41PM +0200, Geert Uytterhoeven wrote: > If dmaengine_prep_slave_sg() or dmaengine_submit() fail, we may leak > unused DMA descriptors. This doesn't apply, I guess it may depend on some of your other DMA related patches but it's not immediately obvious and it's not been sent as part of a series. Can you please check and/or clarify? [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] spi: rspi: Fix leaking of unused DMA descriptors 2014-07-14 18:58 ` [PATCH 1/2] spi: rspi: " Mark Brown @ 2014-08-05 14:34 ` Geert Uytterhoeven 0 siblings, 0 replies; 5+ messages in thread From: Geert Uytterhoeven @ 2014-08-05 14:34 UTC (permalink / raw) To: Mark Brown Cc: Geert Uytterhoeven, Laurent Pinchart, linux-spi, dmaengine, Linux-sh list, linux-kernel Hi Mark, On Mon, Jul 14, 2014 at 8:58 PM, Mark Brown <broonie@kernel.org> wrote: > On Fri, Jul 11, 2014 at 06:06:41PM +0200, Geert Uytterhoeven wrote: >> If dmaengine_prep_slave_sg() or dmaengine_submit() fail, we may leak >> unused DMA descriptors. > > This doesn't apply, I guess it may depend on some of your other DMA > related patches but it's not immediately obvious and it's not been sent > as part of a series. Can you please check and/or clarify? Indeed, this (and the rspi one) depended on the two "Handle dmaengine_prep_slave_single() failures gracefully" patches. Unless you recover them from e.g. patchwork, I'll resend them with my next batch. Sorry for the fuzz. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-08-05 14:34 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-07-11 16:06 [PATCH 1/2] spi: rspi: Fix leaking of unused DMA descriptors Geert Uytterhoeven 2014-07-11 16:06 ` [PATCH 2/2] spi: sh-msiof: " Geert Uytterhoeven 2014-07-14 18:59 ` Mark Brown 2014-07-14 18:58 ` [PATCH 1/2] spi: rspi: " Mark Brown 2014-08-05 14:34 ` Geert Uytterhoeven
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®