diff options
Diffstat (limited to 'patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch')
-rw-r--r-- | patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch b/patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch new file mode 100644 index 0000000..41e012f --- /dev/null +++ b/patches/linux-3.7-rc6/0008-dmaengine-edma-fix-slave-config-dependency-on-direct.patch @@ -0,0 +1,144 @@ +From 10e28276286e519e3be5d9ffb783bf77d48fc3ed Mon Sep 17 00:00:00 2001 +From: Matt Porter <mporter@ti.com> +Date: Tue, 18 Sep 2012 18:57:15 +0000 +Subject: [PATCH] dmaengine: edma: fix slave config dependency on direction + +The edma_slave_config() implementation depends on the +direction field such that it will not properly configure +a slave channel when called without direction set. + +This fixes the implementation so that the slave config +is copied as is and prep_slave_sg() handles the +direction dependent handling. spi-omap2-mcspi and +omap_hsmmc both expose this bug as they configure the +slave channel config from a common path with an unconfigured +direction field. + +Signed-off-by: Matt Porter <mporter@ti.com> +--- + drivers/dma/edma.c | 55 ++++++++++++++++++++++++++-------------------------- + 1 file changed, 27 insertions(+), 28 deletions(-) + +diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c +index 05aea3c..fdcf079 100644 +--- a/drivers/dma/edma.c ++++ b/drivers/dma/edma.c +@@ -69,9 +69,7 @@ struct edma_chan { + int ch_num; + bool alloced; + int slot[EDMA_MAX_SLOTS]; +- dma_addr_t addr; +- int addr_width; +- int maxburst; ++ struct dma_slave_config cfg; + }; + + struct edma_cc { +@@ -178,29 +176,14 @@ static int edma_terminate_all(struct edma_chan *echan) + return 0; + } + +- + static int edma_slave_config(struct edma_chan *echan, +- struct dma_slave_config *config) ++ struct dma_slave_config *cfg) + { +- if ((config->src_addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES) || +- (config->dst_addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)) ++ if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || ++ cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) + return -EINVAL; + +- if (config->direction == DMA_MEM_TO_DEV) { +- if (config->dst_addr) +- echan->addr = config->dst_addr; +- if (config->dst_addr_width) +- echan->addr_width = config->dst_addr_width; +- if (config->dst_maxburst) +- echan->maxburst = config->dst_maxburst; +- } else if (config->direction == DMA_DEV_TO_MEM) { +- if (config->src_addr) +- echan->addr = config->src_addr; +- if (config->src_addr_width) +- echan->addr_width = config->src_addr_width; +- if (config->src_maxburst) +- echan->maxburst = config->src_maxburst; +- } ++ memcpy(&echan->cfg, cfg, sizeof(echan->cfg)); + + return 0; + } +@@ -235,6 +218,9 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + struct edma_chan *echan = to_edma_chan(chan); + struct device *dev = chan->device->dev; + struct edma_desc *edesc; ++ dma_addr_t dev_addr; ++ enum dma_slave_buswidth dev_width; ++ u32 burst; + struct scatterlist *sg; + int i; + int acnt, bcnt, ccnt, src, dst, cidx; +@@ -243,7 +229,20 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + if (unlikely(!echan || !sgl || !sg_len)) + return NULL; + +- if (echan->addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { ++ if (direction == DMA_DEV_TO_MEM) { ++ dev_addr = echan->cfg.src_addr; ++ dev_width = echan->cfg.src_addr_width; ++ burst = echan->cfg.src_maxburst; ++ } else if (direction == DMA_MEM_TO_DEV) { ++ dev_addr = echan->cfg.dst_addr; ++ dev_width = echan->cfg.dst_addr_width; ++ burst = echan->cfg.dst_maxburst; ++ } else { ++ dev_err(dev, "%s: bad direction?\n", __func__); ++ return NULL; ++ } ++ ++ if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { + dev_err(dev, "Undefined slave buswidth\n"); + return NULL; + } +@@ -275,14 +274,14 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + } + } + +- acnt = echan->addr_width; ++ acnt = dev_width; + + /* + * If the maxburst is equal to the fifo width, use + * A-synced transfers. This allows for large contiguous + * buffer transfers using only one PaRAM set. + */ +- if (echan->maxburst == 1) { ++ if (burst == 1) { + edesc->absync = false; + ccnt = sg_dma_len(sg) / acnt / (SZ_64K - 1); + bcnt = sg_dma_len(sg) / acnt - ccnt * (SZ_64K - 1); +@@ -302,7 +301,7 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + */ + } else { + edesc->absync = true; +- bcnt = echan->maxburst; ++ bcnt = burst; + ccnt = sg_dma_len(sg) / (acnt * bcnt); + if (ccnt > (SZ_64K - 1)) { + dev_err(dev, "Exceeded max SG segment size\n"); +@@ -313,13 +312,13 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg( + + if (direction == DMA_MEM_TO_DEV) { + src = sg_dma_address(sg); +- dst = echan->addr; ++ dst = dev_addr; + src_bidx = acnt; + src_cidx = cidx; + dst_bidx = 0; + dst_cidx = 0; + } else { +- src = echan->addr; ++ src = dev_addr; + dst = sg_dma_address(sg); + src_bidx = 0; + src_cidx = 0; |