From fba9024580be3eed90cce59f776fc27e6ca8fbc9 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 8 Mar 2016 09:49:16 +0000
Subject: [PATCH] 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);