Skip to content

bcm2835-sdhost: Only claim one DMA channel #1329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions arch/arm/boot/dts/bcm2708_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,8 @@
reg = <0x7e202000 0x100>;
interrupts = <2 24>;
clocks = <&clk_core>;
dmas = <&dma 13>,
<&dma 13>;
dma-names = "tx", "rx";
dmas = <&dma 13>;
dma-names = "rx-tx";
brcm,overclock-50 = <0>;
brcm,pio-limit = <1>;
status = "disabled";
Expand Down Expand Up @@ -233,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
Original file line number Diff line number Diff line change
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
70 changes: 48 additions & 22 deletions drivers/mmc/host/bcm2835-sdhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,10 @@ struct bcm2835_host {
unsigned int debug:1; /* Enable debug output */

/*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; /* Channel in used */
struct dma_chan *dma_chan_rxtx; /* DMA channel for reads and writes */
struct dma_chan *dma_chan; /* Channel in use */
struct dma_slave_config dma_cfg_rx;
struct dma_slave_config dma_cfg_tx;
struct dma_async_tx_descriptor *dma_desc;
u32 dma_dir;
u32 drain_words;
Expand Down Expand Up @@ -771,12 +772,11 @@ static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host,
log_event("PRD<", (u32)data, 0);
pr_debug("bcm2835_sdhost_prepare_dma()\n");

dma_chan = host->dma_chan_rxtx;
if (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;
}
Expand Down Expand Up @@ -813,6 +813,12 @@ static void bcm2835_sdhost_prepare_dma(struct bcm2835_host *host,
host->drain_words = len/4;
}

/* 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);

len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
dir_data);

Expand Down Expand Up @@ -1805,28 +1811,46 @@ int bcm2835_sdhost_add_host(struct bcm2835_host *host)
spin_lock_init(&host->lock);

if (host->allow_dma) {
if (IS_ERR_OR_NULL(host->dma_chan_tx) ||
IS_ERR_OR_NULL(host->dma_chan_rx)) {
pr_err("%s: unable to initialise DMA channels. "
if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) {
pr_err("%s: unable to initialise DMA channel. "
"Falling back to PIO\n",
mmc_hostname(mmc));
host->use_dma = false;
} else {
host->use_dma = true;

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

/* Validate the slave configurations */

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

cfg.direction = DMA_DEV_TO_MEM;
cfg.src_addr = host->bus_addr + SDDATA;
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 + SDDATA;
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. "
"Falling back to PIO\n",
mmc_hostname(mmc));
dma_release_channel(host->dma_chan_rxtx);
host->dma_chan_rxtx = NULL;
host->use_dma = false;
}
}
} else {
host->use_dma = false;
Expand Down Expand Up @@ -1948,19 +1972,21 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)

if (host->allow_dma) {
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 =
host->dma_chan_rxtx =
dma_request_channel(mask, NULL, NULL);
}
}
Expand Down