]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dmaengine: dw: Select only supported masters for ACPI devices
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Mon, 4 Nov 2024 09:50:50 +0000 (11:50 +0200)
committerVinod Koul <vkoul@kernel.org>
Mon, 2 Dec 2024 17:05:45 +0000 (22:35 +0530)
The recently submitted fix-commit revealed a problem in the iDMA 32-bit
platform code. Even though the controller supported only a single master
the dw_dma_acpi_filter() method hard-coded two master interfaces with IDs
0 and 1. As a result the sanity check implemented in the commit
b336268dde75 ("dmaengine: dw: Add peripheral bus width verification")
got incorrect interface data width and thus prevented the client drivers
from configuring the DMA-channel with the EINVAL error returned. E.g.,
the next error was printed for the PXA2xx SPI controller driver trying
to configure the requested channels:

> [  164.525604] pxa2xx_spi_pci 0000:00:07.1: DMA slave config failed
> [  164.536105] pxa2xx_spi_pci 0000:00:07.1: failed to get DMA TX descriptor
> [  164.543213] spidev spi-SPT0001:00: SPI transfer failed: -16

The problem would have been spotted much earlier if the iDMA 32-bit
controller supported more than one master interfaces. But since it
supports just a single master and the iDMA 32-bit specific code just
ignores the master IDs in the CTLLO preparation method, the issue has
been gone unnoticed so far.

Fix the problem by specifying the default master ID for both memory
and peripheral devices in the driver data. Thus the issue noticed for
the iDMA 32-bit controllers will be eliminated and the ACPI-probed
DW DMA controllers will be configured with the correct master ID by
default.

Cc: stable@vger.kernel.org
Fixes: b336268dde75 ("dmaengine: dw: Add peripheral bus width verification")
Fixes: 199244d69458 ("dmaengine: dw: add support of iDMA 32-bit hardware")
Reported-by: Ferry Toth <fntoth@gmail.com>
Closes: https://lore.kernel.org/dmaengine/ZuXbCKUs1iOqFu51@black.fi.intel.com/
Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Closes: https://lore.kernel.org/dmaengine/ZuXgI-VcHpMgbZ91@black.fi.intel.com/
Tested-by: Ferry Toth <fntoth@gmail.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20241104095142.157925-1-andriy.shevchenko@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/dw/acpi.c
drivers/dma/dw/internal.h
drivers/dma/dw/pci.c

index c510c109d2c3ad20eb5de6e2d4625759baa3846d..b6452fffa657ad3f37b0008967171529cb07ea85 100644 (file)
@@ -8,13 +8,15 @@
 
 static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
 {
+       struct dw_dma *dw = to_dw_dma(chan->device);
+       struct dw_dma_chip_pdata *data = dev_get_drvdata(dw->dma.dev);
        struct acpi_dma_spec *dma_spec = param;
        struct dw_dma_slave slave = {
                .dma_dev = dma_spec->dev,
                .src_id = dma_spec->slave_id,
                .dst_id = dma_spec->slave_id,
-               .m_master = 0,
-               .p_master = 1,
+               .m_master = data->m_master,
+               .p_master = data->p_master,
        };
 
        return dw_dma_filter(chan, &slave);
index 563ce73488db32e5a1ad6fd0db0d6920c1a995ef..f1bd06a20cd611dea57321f614cd5ec9815aea17 100644 (file)
@@ -51,11 +51,15 @@ struct dw_dma_chip_pdata {
        int (*probe)(struct dw_dma_chip *chip);
        int (*remove)(struct dw_dma_chip *chip);
        struct dw_dma_chip *chip;
+       u8 m_master;
+       u8 p_master;
 };
 
 static __maybe_unused const struct dw_dma_chip_pdata dw_dma_chip_pdata = {
        .probe = dw_dma_probe,
        .remove = dw_dma_remove,
+       .m_master = 0,
+       .p_master = 1,
 };
 
 static const struct dw_dma_platform_data idma32_pdata = {
@@ -72,6 +76,8 @@ static __maybe_unused const struct dw_dma_chip_pdata idma32_chip_pdata = {
        .pdata = &idma32_pdata,
        .probe = idma32_dma_probe,
        .remove = idma32_dma_remove,
+       .m_master = 0,
+       .p_master = 0,
 };
 
 static const struct dw_dma_platform_data xbar_pdata = {
@@ -88,6 +94,8 @@ static __maybe_unused const struct dw_dma_chip_pdata xbar_chip_pdata = {
        .pdata = &xbar_pdata,
        .probe = idma32_dma_probe,
        .remove = idma32_dma_remove,
+       .m_master = 0,
+       .p_master = 0,
 };
 
 #endif /* _DMA_DW_INTERNAL_H */
index ad2d4d012cf729ff6780b4da041420bc58634250..e8a0eb81726a5655363445bfff00a0774374810a 100644 (file)
@@ -56,10 +56,10 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        if (ret)
                return ret;
 
-       dw_dma_acpi_controller_register(chip->dw);
-
        pci_set_drvdata(pdev, data);
 
+       dw_dma_acpi_controller_register(chip->dw);
+
        return 0;
 }