Skip to content

Commit

Permalink
spi: dw: Add dma controller capability checks
Browse files Browse the repository at this point in the history
Check capabilities of DMA controller during init to make sure it is
capable of handling MEM2DEV for tx channel, DEV2MEM for rx channel
and store addr_width capabilities to check per transfer to make sure the
bits/word requirement can be met for that transfer.

Signed-off-by: Joy Chakraborty <joychakr@google.com>
  • Loading branch information
Joy Chakraborty authored and intel-lab-lkp committed Mar 26, 2023
1 parent 80de96d commit 9962c1a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 11 deletions.
54 changes: 43 additions & 11 deletions drivers/spi/spi-dw-dma.c
Expand Up @@ -23,6 +23,8 @@
#define DW_SPI_TX_BUSY 1
#define DW_SPI_TX_BURST_LEVEL 16

static inline enum dma_slave_buswidth dw_spi_dma_convert_width(u8 n_bytes);

static bool dw_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{
struct dw_dma_slave *s = param;
Expand Down Expand Up @@ -72,12 +74,15 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
dw_writel(dws, DW_SPI_DMATDLR, dws->txburst);
}

static void dw_spi_dma_sg_burst_init(struct dw_spi *dws)
static int dw_spi_dma_caps_init(struct dw_spi *dws)
{
int ret;
struct dma_slave_caps tx = {0}, rx = {0};

dma_get_slave_caps(dws->txchan, &tx);
dma_get_slave_caps(dws->rxchan, &rx);
ret = dma_get_slave_caps(dws->txchan, &tx);
ret |= dma_get_slave_caps(dws->rxchan, &rx);
if (ret)
return ret;

if (tx.max_sg_burst > 0 && rx.max_sg_burst > 0)
dws->dma_sg_burst = min(tx.max_sg_burst, rx.max_sg_burst);
Expand All @@ -87,6 +92,18 @@ static void dw_spi_dma_sg_burst_init(struct dw_spi *dws)
dws->dma_sg_burst = rx.max_sg_burst;
else
dws->dma_sg_burst = 0;

/*
* Assuming both channels belong to the same DMA controller hence the
* address width capabilities most likely would be the same.
*/
dws->dma_addr_widths = tx.dst_addr_widths & rx.src_addr_widths;

if (!(tx.directions & BIT(DMA_MEM_TO_DEV) &&
rx.directions & BIT(DMA_DEV_TO_MEM)))
return -ENXIO;

return 0;
}

static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
Expand All @@ -95,6 +112,7 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
struct dw_dma_slave dma_rx = { .src_id = 0 }, *rx = &dma_rx;
struct pci_dev *dma_dev;
dma_cap_mask_t mask;
int ret = -EBUSY;

/*
* Get pci device for DMA controller, currently it could only
Expand Down Expand Up @@ -124,20 +142,24 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)

init_completion(&dws->dma_completion);

dw_spi_dma_maxburst_init(dws);
ret = dw_spi_dma_caps_init(dws);
if (ret)
goto free_txchan;

dw_spi_dma_sg_burst_init(dws);
dw_spi_dma_maxburst_init(dws);

pci_dev_put(dma_dev);

return 0;

free_txchan:
dma_release_channel(dws->txchan);
dws->txchan = NULL;
free_rxchan:
dma_release_channel(dws->rxchan);
dws->rxchan = NULL;
err_exit:
pci_dev_put(dma_dev);
return -EBUSY;
return ret;
}

static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
Expand All @@ -163,12 +185,16 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)

init_completion(&dws->dma_completion);

dw_spi_dma_maxburst_init(dws);
ret = dw_spi_dma_caps_init(dws);
if (ret)
goto free_txchan;

dw_spi_dma_sg_burst_init(dws);
dw_spi_dma_maxburst_init(dws);

return 0;

free_txchan:
dma_release_channel(dws->txchan);
dws->txchan = NULL;
free_rxchan:
dma_release_channel(dws->rxchan);
dws->rxchan = NULL;
Expand Down Expand Up @@ -202,8 +228,14 @@ static bool dw_spi_can_dma(struct spi_controller *master,
struct spi_device *spi, struct spi_transfer *xfer)
{
struct dw_spi *dws = spi_controller_get_devdata(master);
enum dma_slave_buswidth dma_bus_width;

if (xfer->len <= dws->fifo_len)
return false;

dma_bus_width = dw_spi_dma_convert_width(dws->n_bytes);

return xfer->len > dws->fifo_len;
return dws->dma_addr_widths & BIT(dma_bus_width);
}

static enum dma_slave_buswidth dw_spi_dma_convert_width(u8 n_bytes)
Expand Down
1 change: 1 addition & 0 deletions drivers/spi/spi-dw.h
Expand Up @@ -190,6 +190,7 @@ struct dw_spi {
struct dma_chan *rxchan;
u32 rxburst;
u32 dma_sg_burst;
u32 dma_addr_widths;
unsigned long dma_chan_busy;
dma_addr_t dma_addr; /* phy address of the Data register */
const struct dw_spi_dma_ops *dma_ops;
Expand Down

0 comments on commit 9962c1a

Please sign in to comment.