diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch new file mode 100644 index 0000000000..8f224faf88 --- /dev/null +++ b/target/linux/brcm2708/patches-4.4/0176-bcm2835-mmc-Only-claim-one-DMA-channel.patch @@ -0,0 +1,170 @@ +From af80d75abc7604cd9eb1788b0171148d000db09d Mon Sep 17 00:00:00 2001 +From: Phil Elwell <phil@raspberrypi.org> +Date: Tue, 8 Mar 2016 09:49:16 +0000 +Subject: [PATCH 176/180] bcm2835-mmc: Only claim one DMA channel + +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: https://github.com/raspberrypi/linux/issues/1327 + +Signed-off-by: Phil Elwell <phil@raspberrypi.org> +--- + arch/arm/boot/dts/bcm2708_common.dtsi | 5 +-- + drivers/mmc/host/bcm2835-mmc.c | 69 +++++++++++++++++++++++++---------- + 2 files changed, 51 insertions(+), 23 deletions(-) + +--- a/arch/arm/boot/dts/bcm2708_common.dtsi ++++ b/arch/arm/boot/dts/bcm2708_common.dtsi +@@ -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"; + }; +--- a/drivers/mmc/host/bcm2835-mmc.c ++++ b/drivers/mmc/host/bcm2835-mmc.c +@@ -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; +@@ -342,7 +343,7 @@ static void bcm2835_mmc_dma_complete(voi + + 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, +@@ -493,16 +494,21 @@ static void bcm2835_mmc_transfer_dma(str + 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); +@@ -936,7 +942,7 @@ static void bcm2835_mmc_data_irq(struct + 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, +@@ -1316,28 +1322,47 @@ static int bcm2835_mmc_add_host(struct b + 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; +@@ -1416,16 +1441,20 @@ static int bcm2835_mmc_probe(struct plat + + #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); |