Skip to content

Commit

Permalink
bcm2835-mmc: Only claim one DMA channel
Browse files Browse the repository at this point in the history
With both MMC controllers enabled there are few DMA channels left. The
bcm2835-mmc driver only uses DMA in one direction at a time, so it
doesn't need to claim two channels.

See: #1327

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
  • Loading branch information
Phil Elwell authored and popcornmix committed Mar 16, 2016
1 parent 1131510 commit ea4b1c5
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 23 deletions.
5 changes: 2 additions & 3 deletions arch/arm/boot/dts/bcm2708_common.dtsi
Expand Up @@ -232,9 +232,8 @@
reg = <0x7e300000 0x100>;
interrupts = <2 30>;
clocks = <&clk_mmc>;
dmas = <&dma 11>,
<&dma 11>;
dma-names = "tx", "rx";
dmas = <&dma 11>;
dma-names = "rx-tx";
brcm,overclock-50 = <0>;
status = "disabled";
};
Expand Down
69 changes: 49 additions & 20 deletions drivers/mmc/host/bcm2835-mmc.c
Expand Up @@ -108,8 +108,9 @@ struct bcm2835_host {
u32 shadow;

/*DMA part*/
struct dma_chan *dma_chan_rx; /* DMA channel for reads */
struct dma_chan *dma_chan_tx; /* DMA channel for writes */
struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
struct dma_slave_config dma_cfg_rx;
struct dma_slave_config dma_cfg_tx;
struct dma_async_tx_descriptor *tx_desc; /* descriptor */

bool have_dma;
Expand Down Expand Up @@ -342,7 +343,7 @@ static void bcm2835_mmc_dma_complete(void *param)

if (host->data && !(host->data->flags & MMC_DATA_WRITE)) {
/* otherwise handled in SDHCI IRQ */
dma_chan = host->dma_chan_rx;
dma_chan = host->dma_chan_rxtx;
dir_data = DMA_FROM_DEVICE;

dma_unmap_sg(dma_chan->device->dev,
Expand Down Expand Up @@ -493,16 +494,21 @@ static void bcm2835_mmc_transfer_dma(struct bcm2835_host *host)
if (host->blocks == 0)
return;

dma_chan = host->dma_chan_rxtx;
if (host->data->flags & MMC_DATA_READ) {
dma_chan = host->dma_chan_rx;
dir_data = DMA_FROM_DEVICE;
dir_slave = DMA_DEV_TO_MEM;
} else {
dma_chan = host->dma_chan_tx;
dir_data = DMA_TO_DEVICE;
dir_slave = DMA_MEM_TO_DEV;
}

/* The parameters have already been validated, so this will not fail */
(void)dmaengine_slave_config(dma_chan,
(dir_data == DMA_FROM_DEVICE) ?
&host->dma_cfg_rx :
&host->dma_cfg_tx);

BUG_ON(!dma_chan->device);
BUG_ON(!dma_chan->device->dev);
BUG_ON(!host->data->sg);
Expand Down Expand Up @@ -936,7 +942,7 @@ static void bcm2835_mmc_data_irq(struct bcm2835_host *host, u32 intmask)
if (host->data->flags & MMC_DATA_WRITE) {
/* IRQ handled here */

dma_chan = host->dma_chan_tx;
dma_chan = host->dma_chan_rxtx;
dir_data = DMA_TO_DEVICE;
dma_unmap_sg(dma_chan->device->dev,
host->data->sg, host->data->sg_len,
Expand Down Expand Up @@ -1316,28 +1322,47 @@ static int bcm2835_mmc_add_host(struct bcm2835_host *host)
dev_info(dev, "Forcing PIO mode\n");
host->have_dma = false;
#else
if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
IS_ERR_OR_NULL(host->dma_chan_rx)) {
dev_err(dev, "%s: Unable to initialise DMA channels. Falling back to PIO\n",
if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
dev_err(dev, "%s: Unable to initialise DMA channel. Falling back to PIO\n",
DRIVER_NAME);
host->have_dma = false;
} else {
dev_info(dev, "DMA channels allocated");
host->have_dma = true;
dev_info(dev, "DMA channel allocated");

cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.slave_id = 11; /* DREQ channel */

/* Validate the slave configurations */

cfg.direction = DMA_MEM_TO_DEV;
cfg.src_addr = 0;
cfg.dst_addr = host->bus_addr + SDHCI_BUFFER;
ret = dmaengine_slave_config(host->dma_chan_tx, &cfg);

cfg.direction = DMA_DEV_TO_MEM;
cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
cfg.dst_addr = 0;
ret = dmaengine_slave_config(host->dma_chan_rx, &cfg);
ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);

if (ret == 0) {
host->dma_cfg_tx = cfg;

cfg.direction = DMA_DEV_TO_MEM;
cfg.src_addr = host->bus_addr + SDHCI_BUFFER;
cfg.dst_addr = 0;

ret = dmaengine_slave_config(host->dma_chan_rxtx, &cfg);
}

if (ret == 0) {
host->dma_cfg_rx = cfg;

host->use_dma = true;
} else {
pr_err("%s: unable to configure DMA channel. "
"Faling back to PIO\n",
mmc_hostname(mmc));
dma_release_channel(host->dma_chan_rxtx);
host->dma_chan_rxtx = NULL;
host->use_dma = false;
}
}
#endif
mmc->max_segs = 128;
Expand Down Expand Up @@ -1416,16 +1441,20 @@ static int bcm2835_mmc_probe(struct platform_device *pdev)

#ifndef FORCE_PIO
if (node) {
host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
host->dma_chan_rxtx = dma_request_slave_channel(dev, "rx-tx");
if (!host->dma_chan_rxtx)
host->dma_chan_rxtx =
dma_request_slave_channel(dev, "tx");
if (!host->dma_chan_rxtx)
host->dma_chan_rxtx =
dma_request_slave_channel(dev, "rx");
} else {
dma_cap_mask_t mask;

dma_cap_zero(mask);
/* we don't care about the channel, any would work */
dma_cap_set(DMA_SLAVE, mask);
host->dma_chan_tx = dma_request_channel(mask, NULL, NULL);
host->dma_chan_rx = dma_request_channel(mask, NULL, NULL);
host->dma_chan_rxtx = dma_request_channel(mask, NULL, NULL);
}
#endif
clk = devm_clk_get(dev, NULL);
Expand Down

0 comments on commit ea4b1c5

Please sign in to comment.