Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: rspi: Fix leaking of unused DMA descriptors

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>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Geert Uytterhoeven and committed by
Mark Brown
3819bc87 7d1311b9

+58 -36
+58 -36
drivers/spi/spi-rspi.c
··· 472 472 dma_cookie_t cookie; 473 473 int ret; 474 474 475 - if (tx) { 476 - desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, 477 - tx->sgl, tx->nents, DMA_TO_DEVICE, 478 - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 479 - if (!desc_tx) 480 - goto no_dma; 481 - 482 - irq_mask |= SPCR_SPTIE; 483 - } 475 + /* First prepare and submit the DMA request(s), as this may fail */ 484 476 if (rx) { 485 477 desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, 486 478 rx->sgl, rx->nents, DMA_FROM_DEVICE, 487 479 DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 488 - if (!desc_rx) 489 - goto no_dma; 480 + if (!desc_rx) { 481 + ret = -EAGAIN; 482 + goto no_dma_rx; 483 + } 484 + 485 + desc_rx->callback = rspi_dma_complete; 486 + desc_rx->callback_param = rspi; 487 + cookie = dmaengine_submit(desc_rx); 488 + if (dma_submit_error(cookie)) { 489 + ret = cookie; 490 + goto no_dma_rx; 491 + } 490 492 491 493 irq_mask |= SPCR_SPRIE; 494 + } 495 + 496 + if (tx) { 497 + desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, 498 + tx->sgl, tx->nents, DMA_TO_DEVICE, 499 + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 500 + if (!desc_tx) { 501 + ret = -EAGAIN; 502 + goto no_dma_tx; 503 + } 504 + 505 + if (rx) { 506 + /* No callback */ 507 + desc_tx->callback = NULL; 508 + } else { 509 + desc_tx->callback = rspi_dma_complete; 510 + desc_tx->callback_param = rspi; 511 + } 512 + cookie = dmaengine_submit(desc_tx); 513 + if (dma_submit_error(cookie)) { 514 + ret = cookie; 515 + goto no_dma_tx; 516 + } 517 + 518 + irq_mask |= SPCR_SPTIE; 492 519 } 493 520 494 521 /* ··· 530 503 rspi_enable_irq(rspi, irq_mask); 531 504 rspi->dma_callbacked = 0; 532 505 533 - if (rx) { 534 - desc_rx->callback = rspi_dma_complete; 535 - desc_rx->callback_param = rspi; 536 - cookie = dmaengine_submit(desc_rx); 537 - if (dma_submit_error(cookie)) 538 - return cookie; 506 + /* Now start DMA */ 507 + if (rx) 539 508 dma_async_issue_pending(rspi->master->dma_rx); 540 - } 541 - if (tx) { 542 - if (rx) { 543 - /* No callback */ 544 - desc_tx->callback = NULL; 545 - } else { 546 - desc_tx->callback = rspi_dma_complete; 547 - desc_tx->callback_param = rspi; 548 - } 549 - cookie = dmaengine_submit(desc_tx); 550 - if (dma_submit_error(cookie)) 551 - return cookie; 509 + if (tx) 552 510 dma_async_issue_pending(rspi->master->dma_tx); 553 - } 554 511 555 512 ret = wait_event_interruptible_timeout(rspi->wait, 556 513 rspi->dma_callbacked, HZ); 557 514 if (ret > 0 && rspi->dma_callbacked) 558 515 ret = 0; 559 - else if (!ret) 516 + else if (!ret) { 517 + dev_err(&rspi->master->dev, "DMA timeout\n"); 560 518 ret = -ETIMEDOUT; 519 + if (tx) 520 + dmaengine_terminate_all(rspi->master->dma_tx); 521 + if (rx) 522 + dmaengine_terminate_all(rspi->master->dma_rx); 523 + } 561 524 562 525 rspi_disable_irq(rspi, irq_mask); 563 526 ··· 558 541 559 542 return ret; 560 543 561 - no_dma: 562 - pr_warn_once("%s %s: DMA not available, falling back to PIO\n", 563 - dev_driver_string(&rspi->master->dev), 564 - dev_name(&rspi->master->dev)); 565 - return -EAGAIN; 544 + no_dma_tx: 545 + if (rx) 546 + dmaengine_terminate_all(rspi->master->dma_rx); 547 + no_dma_rx: 548 + if (ret == -EAGAIN) { 549 + pr_warn_once("%s %s: DMA not available, falling back to PIO\n", 550 + dev_driver_string(&rspi->master->dev), 551 + dev_name(&rspi->master->dev)); 552 + } 553 + return ret; 566 554 } 567 555 568 556 static void rspi_receive_init(const struct rspi_data *rspi)