]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: tegra210-quad: Allocate DMA memory for DMA engine
authorAaron Kling <webgeek1234@gmail.com>
Mon, 25 May 2026 06:47:44 +0000 (01:47 -0500)
committerMark Brown <broonie@kernel.org>
Mon, 1 Jun 2026 14:12:06 +0000 (15:12 +0100)
When the SPI controllers are running in DMA mode, it is the DMA engine
that performs the memory accesses rather than the SPI controller. Pass
the DMA engine's struct device pointer to the DMA API to make sure the
correct DMA operations are used.

Suggested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
Link: https://patch.msgid.link/20260525-tegra194-qspi-iommu-v2-1-a11c53f804b2@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-tegra210-quad.c

index db28dd556484b28de790fc848da023a16347abaf..588a929a97850ab25c1dc4101f620f83cd9dc90b 100644 (file)
@@ -226,11 +226,13 @@ struct tegra_qspi {
        struct completion                       xfer_completion;
        struct spi_transfer                     *curr_xfer;
 
+       struct device                           *rx_dma_dev;
        struct dma_chan                         *rx_dma_chan;
        u32                                     *rx_dma_buf;
        dma_addr_t                              rx_dma_phys;
        struct dma_async_tx_descriptor          *rx_dma_desc;
 
+       struct device                           *tx_dma_dev;
        struct dma_chan                         *tx_dma_chan;
        u32                                     *tx_dma_buf;
        dma_addr_t                              tx_dma_phys;
@@ -574,15 +576,15 @@ static int tegra_qspi_dma_map_xfer(struct tegra_qspi *tqspi, struct spi_transfer
        len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
 
        if (t->tx_buf) {
-               t->tx_dma = dma_map_single(tqspi->dev, (void *)tx_buf, len, DMA_TO_DEVICE);
-               if (dma_mapping_error(tqspi->dev, t->tx_dma))
+               t->tx_dma = dma_map_single(tqspi->tx_dma_dev, (void *)tx_buf, len, DMA_TO_DEVICE);
+               if (dma_mapping_error(tqspi->tx_dma_dev, t->tx_dma))
                        return -ENOMEM;
        }
 
        if (t->rx_buf) {
-               t->rx_dma = dma_map_single(tqspi->dev, (void *)rx_buf, len, DMA_FROM_DEVICE);
-               if (dma_mapping_error(tqspi->dev, t->rx_dma)) {
-                       dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
+               t->rx_dma = dma_map_single(tqspi->rx_dma_dev, (void *)rx_buf, len, DMA_FROM_DEVICE);
+               if (dma_mapping_error(tqspi->rx_dma_dev, t->rx_dma)) {
+                       dma_unmap_single(tqspi->tx_dma_dev, t->tx_dma, len, DMA_TO_DEVICE);
                        return -ENOMEM;
                }
        }
@@ -597,9 +599,9 @@ static void tegra_qspi_dma_unmap_xfer(struct tegra_qspi *tqspi, struct spi_trans
        len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
 
        if (t->tx_buf)
-               dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
+               dma_unmap_single(tqspi->tx_dma_dev, t->tx_dma, len, DMA_TO_DEVICE);
        if (t->rx_buf)
-               dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE);
+               dma_unmap_single(tqspi->rx_dma_dev, t->rx_dma, len, DMA_FROM_DEVICE);
 }
 
 static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t)
@@ -745,7 +747,7 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s
 static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
 {
        if (tqspi->tx_dma_buf) {
-               dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
+               dma_free_coherent(tqspi->tx_dma_dev, tqspi->dma_buf_size,
                                  tqspi->tx_dma_buf, tqspi->tx_dma_phys);
                tqspi->tx_dma_buf = NULL;
        }
@@ -756,7 +758,7 @@ static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
        }
 
        if (tqspi->rx_dma_buf) {
-               dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
+               dma_free_coherent(tqspi->rx_dma_dev, tqspi->dma_buf_size,
                                  tqspi->rx_dma_buf, tqspi->rx_dma_phys);
                tqspi->rx_dma_buf = NULL;
        }
@@ -782,6 +784,7 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
                }
 
                tqspi->rx_dma_chan = dma_chan;
+               tqspi->rx_dma_dev = dmaengine_get_dma_device(tqspi->rx_dma_chan);
 
                dma_chan = dma_request_chan(tqspi->dev, "tx");
                if (IS_ERR(dma_chan)) {
@@ -790,15 +793,19 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
                }
 
                tqspi->tx_dma_chan = dma_chan;
+               tqspi->tx_dma_dev = dmaengine_get_dma_device(tqspi->tx_dma_chan);
        } else {
                if (!device_iommu_mapped(tqspi->dev)) {
                        dev_warn(tqspi->dev,
                                 "IOMMU not enabled in device-tree, falling back to PIO mode\n");
                        return 0;
                }
+
+               tqspi->rx_dma_dev = tqspi->dev;
+               tqspi->tx_dma_dev = tqspi->dev;
        }
 
-       dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
+       dma_buf = dma_alloc_coherent(tqspi->rx_dma_dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
        if (!dma_buf) {
                err = -ENOMEM;
                goto err_out;
@@ -807,7 +814,7 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
        tqspi->rx_dma_buf = dma_buf;
        tqspi->rx_dma_phys = dma_phys;
 
-       dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
+       dma_buf = dma_alloc_coherent(tqspi->tx_dma_dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
        if (!dma_buf) {
                err = -ENOMEM;
                goto err_out;