diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-10-09 18:18:12 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-12-15 00:14:18 -0500 |
commit | d2e015d65fc692475b8513259d6afacd2cded8e8 (patch) | |
tree | e296f8daa8a7ba957d0ae080c71212f77172d382 /arch | |
parent | adfc046740b4161cbb1f0a3ea0d4200e21113489 (diff) |
Blackfin: convert DMA mutex to an atomic and drop redundant code
The DMA channel status field was encoding redundant info wrt the DMA MMR
config register, and it was doing an incomplete job of checking all DMA
channels (some drivers write directly to the config register). So drop
the tristate field in favor of a binary atomic field. This simplifies
the code in general, removes the implicit need for sleeping, and forces
the suspend code to handle all channels properly.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/blackfin/include/asm/dma.h | 17 | ||||
-rw-r--r-- | arch/blackfin/kernel/bfin_dma_5xx.c | 31 |
2 files changed, 13 insertions, 35 deletions
diff --git a/arch/blackfin/include/asm/dma.h b/arch/blackfin/include/asm/dma.h index c9a59622e23f..e3c0dfa73d1b 100644 --- a/arch/blackfin/include/asm/dma.h +++ b/arch/blackfin/include/asm/dma.h | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
12 | #include <mach/dma.h> | 12 | #include <mach/dma.h> |
13 | #include <asm/atomic.h> | ||
13 | #include <asm/blackfin.h> | 14 | #include <asm/blackfin.h> |
14 | #include <asm/page.h> | 15 | #include <asm/page.h> |
15 | 16 | ||
@@ -19,11 +20,6 @@ | |||
19 | * Generic DMA Declarations | 20 | * Generic DMA Declarations |
20 | * | 21 | * |
21 | ****************************************************************************/ | 22 | ****************************************************************************/ |
22 | enum dma_chan_status { | ||
23 | DMA_CHANNEL_FREE, | ||
24 | DMA_CHANNEL_REQUESTED, | ||
25 | DMA_CHANNEL_ENABLED, | ||
26 | }; | ||
27 | 23 | ||
28 | /*------------------------- | 24 | /*------------------------- |
29 | * config reg bits value | 25 | * config reg bits value |
@@ -104,11 +100,9 @@ struct dma_register { | |||
104 | 100 | ||
105 | }; | 101 | }; |
106 | 102 | ||
107 | struct mutex; | ||
108 | struct dma_channel { | 103 | struct dma_channel { |
109 | struct mutex dmalock; | ||
110 | const char *device_id; | 104 | const char *device_id; |
111 | enum dma_chan_status chan_status; | 105 | atomic_t chan_status; |
112 | volatile struct dma_register *regs; | 106 | volatile struct dma_register *regs; |
113 | struct dmasg *sg; /* large mode descriptor */ | 107 | struct dmasg *sg; /* large mode descriptor */ |
114 | unsigned int irq; | 108 | unsigned int irq; |
@@ -220,24 +214,19 @@ static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize | |||
220 | 214 | ||
221 | static inline int dma_channel_active(unsigned int channel) | 215 | static inline int dma_channel_active(unsigned int channel) |
222 | { | 216 | { |
223 | if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) | 217 | return atomic_read(&dma_ch[channel].chan_status); |
224 | return 0; | ||
225 | else | ||
226 | return 1; | ||
227 | } | 218 | } |
228 | 219 | ||
229 | static inline void disable_dma(unsigned int channel) | 220 | static inline void disable_dma(unsigned int channel) |
230 | { | 221 | { |
231 | dma_ch[channel].regs->cfg &= ~DMAEN; | 222 | dma_ch[channel].regs->cfg &= ~DMAEN; |
232 | SSYNC(); | 223 | SSYNC(); |
233 | dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; | ||
234 | } | 224 | } |
235 | static inline void enable_dma(unsigned int channel) | 225 | static inline void enable_dma(unsigned int channel) |
236 | { | 226 | { |
237 | dma_ch[channel].regs->curr_x_count = 0; | 227 | dma_ch[channel].regs->curr_x_count = 0; |
238 | dma_ch[channel].regs->curr_y_count = 0; | 228 | dma_ch[channel].regs->curr_y_count = 0; |
239 | dma_ch[channel].regs->cfg |= DMAEN; | 229 | dma_ch[channel].regs->cfg |= DMAEN; |
240 | dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED; | ||
241 | } | 230 | } |
242 | void free_dma(unsigned int channel); | 231 | void free_dma(unsigned int channel); |
243 | int request_dma(unsigned int channel, const char *device_id); | 232 | int request_dma(unsigned int channel, const char *device_id); |
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 3946aff4f414..639dcee5611c 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c | |||
@@ -37,9 +37,8 @@ static int __init blackfin_dma_init(void) | |||
37 | printk(KERN_INFO "Blackfin DMA Controller\n"); | 37 | printk(KERN_INFO "Blackfin DMA Controller\n"); |
38 | 38 | ||
39 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | 39 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { |
40 | dma_ch[i].chan_status = DMA_CHANNEL_FREE; | 40 | atomic_set(&dma_ch[i].chan_status, 0); |
41 | dma_ch[i].regs = dma_io_base_addr[i]; | 41 | dma_ch[i].regs = dma_io_base_addr[i]; |
42 | mutex_init(&(dma_ch[i].dmalock)); | ||
43 | } | 42 | } |
44 | /* Mark MEMDMA Channel 0 as requested since we're using it internally */ | 43 | /* Mark MEMDMA Channel 0 as requested since we're using it internally */ |
45 | request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy"); | 44 | request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy"); |
@@ -60,7 +59,7 @@ static int proc_dma_show(struct seq_file *m, void *v) | |||
60 | int i; | 59 | int i; |
61 | 60 | ||
62 | for (i = 0; i < MAX_DMA_CHANNELS; ++i) | 61 | for (i = 0; i < MAX_DMA_CHANNELS; ++i) |
63 | if (dma_ch[i].chan_status != DMA_CHANNEL_FREE) | 62 | if (dma_channel_active(i)) |
64 | seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id); | 63 | seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id); |
65 | 64 | ||
66 | return 0; | 65 | return 0; |
@@ -107,20 +106,11 @@ int request_dma(unsigned int channel, const char *device_id) | |||
107 | } | 106 | } |
108 | #endif | 107 | #endif |
109 | 108 | ||
110 | mutex_lock(&(dma_ch[channel].dmalock)); | 109 | if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) { |
111 | |||
112 | if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED) | ||
113 | || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) { | ||
114 | mutex_unlock(&(dma_ch[channel].dmalock)); | ||
115 | pr_debug("DMA CHANNEL IN USE \n"); | 110 | pr_debug("DMA CHANNEL IN USE \n"); |
116 | return -EBUSY; | 111 | return -EBUSY; |
117 | } else { | ||
118 | dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED; | ||
119 | pr_debug("DMA CHANNEL IS ALLOCATED \n"); | ||
120 | } | 112 | } |
121 | 113 | ||
122 | mutex_unlock(&(dma_ch[channel].dmalock)); | ||
123 | |||
124 | #ifdef CONFIG_BF54x | 114 | #ifdef CONFIG_BF54x |
125 | if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { | 115 | if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { |
126 | unsigned int per_map; | 116 | unsigned int per_map; |
@@ -149,7 +139,7 @@ EXPORT_SYMBOL(request_dma); | |||
149 | int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data) | 139 | int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data) |
150 | { | 140 | { |
151 | BUG_ON(channel >= MAX_DMA_CHANNELS || | 141 | BUG_ON(channel >= MAX_DMA_CHANNELS || |
152 | dma_ch[channel].chan_status == DMA_CHANNEL_FREE); | 142 | !atomic_read(&dma_ch[channel].chan_status)); |
153 | 143 | ||
154 | if (callback != NULL) { | 144 | if (callback != NULL) { |
155 | int ret; | 145 | int ret; |
@@ -184,7 +174,7 @@ void free_dma(unsigned int channel) | |||
184 | { | 174 | { |
185 | pr_debug("freedma() : BEGIN \n"); | 175 | pr_debug("freedma() : BEGIN \n"); |
186 | BUG_ON(channel >= MAX_DMA_CHANNELS || | 176 | BUG_ON(channel >= MAX_DMA_CHANNELS || |
187 | dma_ch[channel].chan_status == DMA_CHANNEL_FREE); | 177 | !atomic_read(&dma_ch[channel].chan_status)); |
188 | 178 | ||
189 | /* Halt the DMA */ | 179 | /* Halt the DMA */ |
190 | disable_dma(channel); | 180 | disable_dma(channel); |
@@ -194,9 +184,7 @@ void free_dma(unsigned int channel) | |||
194 | free_irq(dma_ch[channel].irq, dma_ch[channel].data); | 184 | free_irq(dma_ch[channel].irq, dma_ch[channel].data); |
195 | 185 | ||
196 | /* Clear the DMA Variable in the Channel */ | 186 | /* Clear the DMA Variable in the Channel */ |
197 | mutex_lock(&(dma_ch[channel].dmalock)); | 187 | atomic_set(&dma_ch[channel].chan_status, 0); |
198 | dma_ch[channel].chan_status = DMA_CHANNEL_FREE; | ||
199 | mutex_unlock(&(dma_ch[channel].dmalock)); | ||
200 | 188 | ||
201 | pr_debug("freedma() : END \n"); | 189 | pr_debug("freedma() : END \n"); |
202 | } | 190 | } |
@@ -210,13 +198,14 @@ int blackfin_dma_suspend(void) | |||
210 | { | 198 | { |
211 | int i; | 199 | int i; |
212 | 200 | ||
213 | for (i = 0; i < MAX_DMA_SUSPEND_CHANNELS; ++i) { | 201 | for (i = 0; i < MAX_DMA_CHANNELS; ++i) { |
214 | if (dma_ch[i].chan_status == DMA_CHANNEL_ENABLED) { | 202 | if (dma_ch[i].regs->cfg & DMAEN) { |
215 | printk(KERN_ERR "DMA Channel %d failed to suspend\n", i); | 203 | printk(KERN_ERR "DMA Channel %d failed to suspend\n", i); |
216 | return -EBUSY; | 204 | return -EBUSY; |
217 | } | 205 | } |
218 | 206 | ||
219 | dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map; | 207 | if (i < MAX_DMA_SUSPEND_CHANNELS) |
208 | dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map; | ||
220 | } | 209 | } |
221 | 210 | ||
222 | return 0; | 211 | return 0; |