diff options
Diffstat (limited to 'packages/linux/linux-2.6.18/dmac-stopping-idle-channel-is-not-fatal.patch')
-rw-r--r-- | packages/linux/linux-2.6.18/dmac-stopping-idle-channel-is-not-fatal.patch | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/packages/linux/linux-2.6.18/dmac-stopping-idle-channel-is-not-fatal.patch b/packages/linux/linux-2.6.18/dmac-stopping-idle-channel-is-not-fatal.patch new file mode 100644 index 0000000000..ed2714d0d7 --- /dev/null +++ b/packages/linux/linux-2.6.18/dmac-stopping-idle-channel-is-not-fatal.patch @@ -0,0 +1,93 @@ +--- + arch/avr32/drivers/dw-dmac.c | 50 ++++++++++++++++++++++++------------------- + 1 file changed, 29 insertions(+), 21 deletions(-) + +Index: linux-2.6.18-avr32/arch/avr32/drivers/dw-dmac.c +=================================================================== +--- linux-2.6.18-avr32.orig/arch/avr32/drivers/dw-dmac.c 2007-01-04 09:56:32.000000000 +0100 ++++ linux-2.6.18-avr32/arch/avr32/drivers/dw-dmac.c 2007-01-04 15:38:13.000000000 +0100 +@@ -7,7 +7,6 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +- + #include <linux/clk.h> + #include <linux/device.h> + #include <linux/dma-mapping.h> +@@ -155,6 +154,21 @@ fail: + return NULL; + } + ++static void cleanup_channel(struct dw_dma_controller *dmac, ++ struct dw_dma_channel *chan) ++{ ++ unsigned int i; ++ ++ if (chan->nr_blocks > 1) { ++ for (i = 0; i < chan->nr_blocks; i++) ++ dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr, ++ chan->block[i].lli_dma_addr); ++ kfree(chan->block); ++ } ++ ++ chan->state = CH_STATE_ALLOCATED; ++} ++ + static int dmac_prepare_request_sg(struct dma_controller *_dmac, + struct dma_request_sg *req) + { +@@ -313,6 +327,7 @@ static int dmac_prepare_request_sg(struc + * SAR, DAR and CTL are initialized from the LLI. We + * only have to enable the LLI bits in CTL. + */ ++ dmac_chan_writel_hi(dmac, req->req.channel, CTL, 0); + dmac_chan_writel_lo(dmac, req->req.channel, LLP, + chan->block[0].lli_dma_addr); + dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27); +@@ -520,33 +535,26 @@ static dma_addr_t dmac_get_current_pos(s + } + + +-static void cleanup_channel(struct dw_dma_controller *dmac, +- struct dw_dma_channel *chan) +-{ +- unsigned int i; +- +- if (chan->nr_blocks > 1) { +- for (i = 0; i < chan->nr_blocks; i++) +- dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr, +- chan->block[i].lli_dma_addr); +- kfree(chan->block); +- } +- +- chan->state = CH_STATE_ALLOCATED; +-} +- + static int dmac_stop_request(struct dma_controller *_dmac, + unsigned int channel) + { + struct dw_dma_controller *dmac = to_dw_dmac(_dmac); ++ struct dw_dma_channel *chan; + + BUG_ON(channel >= DMAC_NR_CHANNELS); + +- BUG_ON(dmac->channel[channel].state != CH_STATE_BUSY); +- +- clear_channel_bit(dmac, CH_EN, channel); +- +- cleanup_channel(dmac, &dmac->channel[channel]); ++ chan = &dmac->channel[channel]; ++ pr_debug("stop: st%u s%08x d%08x l%08x ctl0x%08x:0x%08x\n", ++ chan->state, dmac_chan_readl_lo(dmac, channel, SAR), ++ dmac_chan_readl_lo(dmac, channel, DAR), ++ dmac_chan_readl_lo(dmac, channel, LLP), ++ dmac_chan_readl_hi(dmac, channel, CTL), ++ dmac_chan_readl_lo(dmac, channel, CTL)); ++ ++ if (chan->state == CH_STATE_BUSY) { ++ clear_channel_bit(dmac, CH_EN, channel); ++ cleanup_channel(dmac, &dmac->channel[channel]); ++ } + + return 0; + } |