1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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;
}
|