123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- From 535bf1097beb4279ac4895a61199078672ffc63a Mon Sep 17 00:00:00 2001
- From: Phil Elwell <phil@raspberrypi.org>
- Date: Mon, 7 Mar 2016 16:46:39 +0000
- Subject: [PATCH] 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);
- }
- }
|