summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch')
-rw-r--r--target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch160
1 files changed, 160 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch b/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
new file mode 100644
index 0000000..5f2775d
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0167-bcm2835-sdhost-Only-claim-one-DMA-channel.patch
@@ -0,0 +1,160 @@
+From d6b47c6dc22a1fbe2fcb5c742936a32baad60409 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 7 Mar 2016 16:46:39 +0000
+Subject: [PATCH 167/304] bcm2835-sdhost: Only claim one DMA channel
+
+With both MMC controllers enabled there are few DMA channels left. The
+bcm2835-sdhost 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-sdhost.c | 70 ++++++++++++++++++++++++-----------
+ 2 files changed, 50 insertions(+), 25 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -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";
+--- a/drivers/mmc/host/bcm2835-sdhost.c
++++ b/drivers/mmc/host/bcm2835-sdhost.c
+@@ -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;
+@@ -771,12 +772,11 @@ static void bcm2835_sdhost_prepare_dma(s
+ 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;
+ }
+@@ -813,6 +813,12 @@ static void bcm2835_sdhost_prepare_dma(s
+ 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);
+
+@@ -1805,28 +1811,46 @@ int bcm2835_sdhost_add_host(struct bcm28
+ 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;
+@@ -1948,19 +1972,21 @@ static int bcm2835_sdhost_probe(struct p
+
+ 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);
+ }
+ }