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

The commit cd57d07b1e ("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: cd57d07b1e ("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
This commit is contained in:
Ulf Hansson 2020-09-01 17:04:38 +02:00
Родитель 9d5dcefb7b
Коммит a395acf0f6
2 изменённых файлов: 53 добавлений и 35 удалений

Просмотреть файл

@ -602,7 +602,7 @@ config MMC_GOLDFISH
config MMC_SPI config MMC_SPI
tristate "MMC/SD/SDIO over SPI" tristate "MMC/SD/SDIO over SPI"
depends on SPI_MASTER && HAS_DMA depends on SPI_MASTER
select CRC7 select CRC7
select CRC_ITU_T select CRC_ITU_T
help help

Просмотреть файл

@ -1278,6 +1278,52 @@ mmc_spi_detect_irq(int irq, void *mmc)
return IRQ_HANDLED; 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) static int mmc_spi_probe(struct spi_device *spi)
{ {
void *ones; void *ones;
@ -1374,23 +1420,9 @@ static int mmc_spi_probe(struct spi_device *spi)
if (!host->data) if (!host->data)
goto fail_nobuf1; goto fail_nobuf1;
if (spi->master->dev.parent->dma_mask) { status = mmc_spi_dma_alloc(host);
struct device *dev = spi->master->dev.parent; if (status)
goto fail_dma;
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);
}
/* setup message for status/busy readback */ /* setup message for status/busy readback */
spi_message_init(&host->readback); spi_message_init(&host->readback);
@ -1458,20 +1490,12 @@ static int mmc_spi_probe(struct spi_device *spi)
fail_add_host: fail_add_host:
mmc_remove_host(mmc); mmc_remove_host(mmc);
fail_glue_init: fail_glue_init:
if (host->dma_dev) mmc_spi_dma_free(host);
dma_unmap_single(host->dma_dev, host->data_dma, fail_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:
kfree(host->data); kfree(host->data);
fail_nobuf1: fail_nobuf1:
mmc_free_host(mmc); mmc_free_host(mmc);
mmc_spi_put_pdata(spi); mmc_spi_put_pdata(spi);
nomem: nomem:
kfree(ones); kfree(ones);
return status; return status;
@ -1489,13 +1513,7 @@ static int mmc_spi_remove(struct spi_device *spi)
mmc_remove_host(mmc); mmc_remove_host(mmc);
if (host->dma_dev) { mmc_spi_dma_free(host);
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);
}
kfree(host->data); kfree(host->data);
kfree(host->ones); kfree(host->ones);