Skip to content

Commit d1ca1c5

Browse files
Joy Chakrabortybroonie
authored andcommitted
spi: dw: Add DMA directional capability check
Check capabilities of DMA controller during init to make sure it is capable of handling MEM2DEV for tx channel, DEV2MEM for rx channel. Current DW DMA driver requires both tx and rx channel to be configured and functional for any kind of transfers to take effect including half duplex. Hence, check for both tx and rx direction and fail on unavailbility of either. * tested on Baikal-T1 based system with DW SPI-looped back interface transferring a chunk of data with DFS:8,12,16. Signed-off-by: Joy Chakraborty <joychakr@google.com Reviewed-by: Serge Semin <fancer.lancer@gmail.com Tested-by: Serge Semin <fancer.lancer@gmail.com Link: https://lore.kernel.org/r/20230512104746.1797865-2-joychakr@google.com Signed-off-by: Mark Brown <broonie@kernel.org
1 parent f603a3f commit d1ca1c5

1 file changed

Lines changed: 32 additions & 9 deletions

File tree

drivers/spi/spi-dw-dma.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,22 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
7272
dw_writel(dws, DW_SPI_DMATDLR, dws->txburst);
7373
}
7474

75-
static void dw_spi_dma_sg_burst_init(struct dw_spi *dws)
75+
static int dw_spi_dma_caps_init(struct dw_spi *dws)
7676
{
77-
struct dma_slave_caps tx = {0}, rx = {0};
77+
struct dma_slave_caps tx, rx;
78+
int ret;
79+
80+
ret = dma_get_slave_caps(dws->txchan, &tx);
81+
if (ret)
82+
return ret;
7883

79-
dma_get_slave_caps(dws->txchan, &tx);
80-
dma_get_slave_caps(dws->rxchan, &rx);
84+
ret = dma_get_slave_caps(dws->rxchan, &rx);
85+
if (ret)
86+
return ret;
87+
88+
if (!(tx.directions & BIT(DMA_MEM_TO_DEV) &&
89+
rx.directions & BIT(DMA_DEV_TO_MEM)))
90+
return -ENXIO;
8191

8292
if (tx.max_sg_burst > 0 && rx.max_sg_burst > 0)
8393
dws->dma_sg_burst = min(tx.max_sg_burst, rx.max_sg_burst);
@@ -87,6 +97,8 @@ static void dw_spi_dma_sg_burst_init(struct dw_spi *dws)
8797
dws->dma_sg_burst = rx.max_sg_burst;
8898
else
8999
dws->dma_sg_burst = 0;
100+
101+
return 0;
90102
}
91103

92104
static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
@@ -95,6 +107,7 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
95107
struct dw_dma_slave dma_rx = { .src_id = 0 }, *rx = &dma_rx;
96108
struct pci_dev *dma_dev;
97109
dma_cap_mask_t mask;
110+
int ret = -EBUSY;
98111

99112
/*
100113
* Get pci device for DMA controller, currently it could only
@@ -124,20 +137,25 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
124137

125138
init_completion(&dws->dma_completion);
126139

127-
dw_spi_dma_maxburst_init(dws);
140+
ret = dw_spi_dma_caps_init(dws);
141+
if (ret)
142+
goto free_txchan;
128143

129-
dw_spi_dma_sg_burst_init(dws);
144+
dw_spi_dma_maxburst_init(dws);
130145

131146
pci_dev_put(dma_dev);
132147

133148
return 0;
134149

150+
free_txchan:
151+
dma_release_channel(dws->txchan);
152+
dws->txchan = NULL;
135153
free_rxchan:
136154
dma_release_channel(dws->rxchan);
137155
dws->rxchan = NULL;
138156
err_exit:
139157
pci_dev_put(dma_dev);
140-
return -EBUSY;
158+
return ret;
141159
}
142160

143161
static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
@@ -163,12 +181,17 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
163181

164182
init_completion(&dws->dma_completion);
165183

166-
dw_spi_dma_maxburst_init(dws);
184+
ret = dw_spi_dma_caps_init(dws);
185+
if (ret)
186+
goto free_txchan;
167187

168-
dw_spi_dma_sg_burst_init(dws);
188+
dw_spi_dma_maxburst_init(dws);
169189

170190
return 0;
171191

192+
free_txchan:
193+
dma_release_channel(dws->txchan);
194+
dws->txchan = NULL;
172195
free_rxchan:
173196
dma_release_channel(dws->rxchan);
174197
dws->rxchan = NULL;

0 commit comments

Comments
 (0)