Commit a395acf0 authored by Ulf Hansson's avatar Ulf Hansson

mmc: mmc_spi: Allow the driver to be built when CONFIG_HAS_DMA is unset

The commit cd57d07b ("sh: don't allow non-coherent DMA for NOMMU") made
CONFIG_NO_DMA to be set for some platforms, for good reasons.
Consequentially, CONFIG_HAS_DMA doesn't get set, which makes the DMA
mapping interface to be built as stub functions, but also prevent the
mmc_spi driver from being built as it depends on CONFIG_HAS_DMA.

It turns out that for some odd cases, the driver still relied on the DMA
mapping interface, even if the DMA was not actively being used.

To fixup the behaviour, let's drop the build dependency for CONFIG_HAS_DMA.
Moreover, as to allow the driver to succeed probing, let's move the DMA
initializations behind "#ifdef CONFIG_HAS_DMA".

Fixes: cd57d07b ("sh: don't allow non-coherent DMA for NOMMU")
Reported-by: default avatarRich Felker <dalias@libc.org>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Tested-by: default avatarRich Felker <dalias@libc.org>
Link: https://lore.kernel.org/r/20200901150438.228887-1-ulf.hansson@linaro.org
parent 9d5dcefb
......@@ -602,7 +602,7 @@ config MMC_GOLDFISH
config MMC_SPI
tristate "MMC/SD/SDIO over SPI"
depends on SPI_MASTER && HAS_DMA
depends on SPI_MASTER
select CRC7
select CRC_ITU_T
help
......
......@@ -1278,6 +1278,52 @@ mmc_spi_detect_irq(int irq, void *mmc)
return IRQ_HANDLED;
}
#ifdef CONFIG_HAS_DMA
static int mmc_spi_dma_alloc(struct mmc_spi_host *host)
{
struct spi_device *spi = host->spi;
struct device *dev;
if (!spi->master->dev.parent->dma_mask)
return 0;
dev = spi->master->dev.parent;
host->ones_dma = dma_map_single(dev, host->ones, MMC_SPI_BLOCKSIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, host->ones_dma))
return -ENOMEM;
host->data_dma = dma_map_single(dev, host->data, sizeof(*host->data),
DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev, host->data_dma)) {
dma_unmap_single(dev, host->ones_dma, MMC_SPI_BLOCKSIZE,
DMA_TO_DEVICE);
return -ENOMEM;
}
dma_sync_single_for_cpu(dev, host->data_dma, sizeof(*host->data),
DMA_BIDIRECTIONAL);
host->dma_dev = dev;
return 0;
}
static void mmc_spi_dma_free(struct mmc_spi_host *host)
{
if (!host->dma_dev)
return;
dma_unmap_single(host->dma_dev, host->ones_dma, MMC_SPI_BLOCKSIZE,
DMA_TO_DEVICE);
dma_unmap_single(host->dma_dev, host->data_dma, sizeof(*host->data),
DMA_BIDIRECTIONAL);
}
#else
static inline mmc_spi_dma_alloc(struct mmc_spi_host *host) { return 0; }
static inline void mmc_spi_dma_free(struct mmc_spi_host *host) {}
#endif
static int mmc_spi_probe(struct spi_device *spi)
{
void *ones;
......@@ -1374,23 +1420,9 @@ static int mmc_spi_probe(struct spi_device *spi)
if (!host->data)
goto fail_nobuf1;
if (spi->master->dev.parent->dma_mask) {
struct device *dev = spi->master->dev.parent;
host->dma_dev = dev;
host->ones_dma = dma_map_single(dev, ones,
MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
if (dma_mapping_error(dev, host->ones_dma))
goto fail_ones_dma;
host->data_dma = dma_map_single(dev, host->data,
sizeof(*host->data), DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev, host->data_dma))
goto fail_data_dma;
dma_sync_single_for_cpu(host->dma_dev,
host->data_dma, sizeof(*host->data),
DMA_BIDIRECTIONAL);
}
status = mmc_spi_dma_alloc(host);
if (status)
goto fail_dma;
/* setup message for status/busy readback */
spi_message_init(&host->readback);
......@@ -1458,20 +1490,12 @@ static int mmc_spi_probe(struct spi_device *spi)
fail_add_host:
mmc_remove_host(mmc);
fail_glue_init:
if (host->dma_dev)
dma_unmap_single(host->dma_dev, host->data_dma,
sizeof(*host->data), DMA_BIDIRECTIONAL);
fail_data_dma:
if (host->dma_dev)
dma_unmap_single(host->dma_dev, host->ones_dma,
MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
fail_ones_dma:
mmc_spi_dma_free(host);
fail_dma:
kfree(host->data);
fail_nobuf1:
mmc_free_host(mmc);
mmc_spi_put_pdata(spi);
nomem:
kfree(ones);
return status;
......@@ -1489,13 +1513,7 @@ static int mmc_spi_remove(struct spi_device *spi)
mmc_remove_host(mmc);
if (host->dma_dev) {
dma_unmap_single(host->dma_dev, host->ones_dma,
MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
dma_unmap_single(host->dma_dev, host->data_dma,
sizeof(*host->data), DMA_BIDIRECTIONAL);
}
mmc_spi_dma_free(host);
kfree(host->data);
kfree(host->ones);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment