aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-10-09 18:18:12 -0400
committerMike Frysinger <vapier@gentoo.org>2009-12-15 00:14:18 -0500
commitd2e015d65fc692475b8513259d6afacd2cded8e8 (patch)
treee296f8daa8a7ba957d0ae080c71212f77172d382 /arch
parentadfc046740b4161cbb1f0a3ea0d4200e21113489 (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.h17
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c31
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****************************************************************************/
22enum 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
107struct mutex;
108struct dma_channel { 103struct 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
221static inline int dma_channel_active(unsigned int channel) 215static 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
229static inline void disable_dma(unsigned int channel) 220static 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}
235static inline void enable_dma(unsigned int channel) 225static 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}
242void free_dma(unsigned int channel); 231void free_dma(unsigned int channel);
243int request_dma(unsigned int channel, const char *device_id); 232int 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);
149int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data) 139int 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;