Skip to content

Commit

Permalink
mmc: mmc_spi: Allow the driver to be built when CONFIG_HAS_DMA is unset
Browse files Browse the repository at this point in the history
The commit cd57d07 ("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: cd57d07 ("sh: don't allow non-coherent DMA for NOMMU")
Reported-by: Rich Felker <dalias@libc.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Rich Felker <dalias@libc.org>
Link: https://lore.kernel.org/r/20200901150438.228887-1-ulf.hansson@linaro.org
  • Loading branch information
storulf committed Sep 7, 2020
1 parent 9d5dcef commit a395acf
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 35 deletions.
2 changes: 1 addition & 1 deletion drivers/mmc/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
86 changes: 52 additions & 34 deletions drivers/mmc/host/mmc_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand Down

0 comments on commit a395acf

Please sign in to comment.