diff options
author | Geert Uytterhoeven <geert+renesas@glider.be> | 2014-07-09 06:26:23 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-07-16 17:41:51 -0400 |
commit | 279d2378c9c4f05bbe41b55625b4003871026266 (patch) | |
tree | c07d111eb25b18e62addcd98e311013c8c0e486b /drivers/spi/spi-sh-msiof.c | |
parent | 51fd509046f71471e606f3fd76411d238c3b5d39 (diff) |
spi: sh-msiof: Handle dmaengine_prep_slave_single() failures gracefully
As typically a shmobile SoC has less DMA channels than devices that can use
DMA, we may want to prioritize access to the DMA channels in the future.
This means that dmaengine_prep_slave_single() may start failing
arbitrarily.
Handle dmaengine_prep_slave_single() failures gracefully by falling back to
PIO. This requires moving DMA-specific configuration of the MSIOF device
after the call(s) to dmaengine_prep_slave_single().
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi/spi-sh-msiof.c')
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 9922ed3a4441..373de70baf08 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c | |||
@@ -636,12 +636,6 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, | |||
636 | dma_cookie_t cookie; | 636 | dma_cookie_t cookie; |
637 | int ret; | 637 | int ret; |
638 | 638 | ||
639 | /* 1 stage FIFO watermarks for DMA */ | ||
640 | sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); | ||
641 | |||
642 | /* setup msiof transfer mode registers (32-bit words) */ | ||
643 | sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); | ||
644 | |||
645 | if (tx) { | 639 | if (tx) { |
646 | ier_bits |= IER_TDREQE | IER_TDMAE; | 640 | ier_bits |= IER_TDREQE | IER_TDMAE; |
647 | dma_sync_single_for_device(&p->pdev->dev, p->tx_dma_addr, len, | 641 | dma_sync_single_for_device(&p->pdev->dev, p->tx_dma_addr, len, |
@@ -650,7 +644,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, | |||
650 | p->tx_dma_addr, len, DMA_TO_DEVICE, | 644 | p->tx_dma_addr, len, DMA_TO_DEVICE, |
651 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | 645 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
652 | if (!desc_tx) | 646 | if (!desc_tx) |
653 | return -EIO; | 647 | return -EAGAIN; |
654 | } | 648 | } |
655 | 649 | ||
656 | if (rx) { | 650 | if (rx) { |
@@ -659,8 +653,15 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, | |||
659 | p->rx_dma_addr, len, DMA_FROM_DEVICE, | 653 | p->rx_dma_addr, len, DMA_FROM_DEVICE, |
660 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | 654 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
661 | if (!desc_rx) | 655 | if (!desc_rx) |
662 | return -EIO; | 656 | return -EAGAIN; |
663 | } | 657 | } |
658 | |||
659 | /* 1 stage FIFO watermarks for DMA */ | ||
660 | sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); | ||
661 | |||
662 | /* setup msiof transfer mode registers (32-bit words) */ | ||
663 | sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); | ||
664 | |||
664 | sh_msiof_write(p, IER, ier_bits); | 665 | sh_msiof_write(p, IER, ier_bits); |
665 | 666 | ||
666 | reinit_completion(&p->done); | 667 | reinit_completion(&p->done); |
@@ -822,6 +823,12 @@ static int sh_msiof_transfer_one(struct spi_master *master, | |||
822 | copy32(p->tx_dma_page, tx_buf, l / 4); | 823 | copy32(p->tx_dma_page, tx_buf, l / 4); |
823 | 824 | ||
824 | ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l); | 825 | ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l); |
826 | if (ret == -EAGAIN) { | ||
827 | pr_warn_once("%s %s: DMA not available, falling back to PIO\n", | ||
828 | dev_driver_string(&p->pdev->dev), | ||
829 | dev_name(&p->pdev->dev)); | ||
830 | break; | ||
831 | } | ||
825 | if (ret) | 832 | if (ret) |
826 | return ret; | 833 | return ret; |
827 | 834 | ||