Commit d2e015d6 authored by Mike Frysinger's avatar Mike Frysinger

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: default avatarMike Frysinger <vapier@gentoo.org>
parent adfc0467
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <mach/dma.h> #include <mach/dma.h>
#include <asm/atomic.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -19,11 +20,6 @@ ...@@ -19,11 +20,6 @@
* Generic DMA Declarations * Generic DMA Declarations
* *
****************************************************************************/ ****************************************************************************/
enum dma_chan_status {
DMA_CHANNEL_FREE,
DMA_CHANNEL_REQUESTED,
DMA_CHANNEL_ENABLED,
};
/*------------------------- /*-------------------------
* config reg bits value * config reg bits value
...@@ -104,11 +100,9 @@ struct dma_register { ...@@ -104,11 +100,9 @@ struct dma_register {
}; };
struct mutex;
struct dma_channel { struct dma_channel {
struct mutex dmalock;
const char *device_id; const char *device_id;
enum dma_chan_status chan_status; atomic_t chan_status;
volatile struct dma_register *regs; volatile struct dma_register *regs;
struct dmasg *sg; /* large mode descriptor */ struct dmasg *sg; /* large mode descriptor */
unsigned int irq; unsigned int irq;
...@@ -220,24 +214,19 @@ static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize ...@@ -220,24 +214,19 @@ static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize
static inline int dma_channel_active(unsigned int channel) static inline int dma_channel_active(unsigned int channel)
{ {
if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) return atomic_read(&dma_ch[channel].chan_status);
return 0;
else
return 1;
} }
static inline void disable_dma(unsigned int channel) static inline void disable_dma(unsigned int channel)
{ {
dma_ch[channel].regs->cfg &= ~DMAEN; dma_ch[channel].regs->cfg &= ~DMAEN;
SSYNC(); SSYNC();
dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
} }
static inline void enable_dma(unsigned int channel) static inline void enable_dma(unsigned int channel)
{ {
dma_ch[channel].regs->curr_x_count = 0; dma_ch[channel].regs->curr_x_count = 0;
dma_ch[channel].regs->curr_y_count = 0; dma_ch[channel].regs->curr_y_count = 0;
dma_ch[channel].regs->cfg |= DMAEN; dma_ch[channel].regs->cfg |= DMAEN;
dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
} }
void free_dma(unsigned int channel); void free_dma(unsigned int channel);
int request_dma(unsigned int channel, const char *device_id); int request_dma(unsigned int channel, const char *device_id);
......
...@@ -37,9 +37,8 @@ static int __init blackfin_dma_init(void) ...@@ -37,9 +37,8 @@ static int __init blackfin_dma_init(void)
printk(KERN_INFO "Blackfin DMA Controller\n"); printk(KERN_INFO "Blackfin DMA Controller\n");
for (i = 0; i < MAX_DMA_CHANNELS; i++) { for (i = 0; i < MAX_DMA_CHANNELS; i++) {
dma_ch[i].chan_status = DMA_CHANNEL_FREE; atomic_set(&dma_ch[i].chan_status, 0);
dma_ch[i].regs = dma_io_base_addr[i]; dma_ch[i].regs = dma_io_base_addr[i];
mutex_init(&(dma_ch[i].dmalock));
} }
/* Mark MEMDMA Channel 0 as requested since we're using it internally */ /* Mark MEMDMA Channel 0 as requested since we're using it internally */
request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy"); 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,7 +59,7 @@ static int proc_dma_show(struct seq_file *m, void *v)
int i; int i;
for (i = 0; i < MAX_DMA_CHANNELS; ++i) for (i = 0; i < MAX_DMA_CHANNELS; ++i)
if (dma_ch[i].chan_status != DMA_CHANNEL_FREE) if (dma_channel_active(i))
seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id); seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id);
return 0; return 0;
...@@ -107,20 +106,11 @@ int request_dma(unsigned int channel, const char *device_id) ...@@ -107,20 +106,11 @@ int request_dma(unsigned int channel, const char *device_id)
} }
#endif #endif
mutex_lock(&(dma_ch[channel].dmalock)); if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) {
if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
|| (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
mutex_unlock(&(dma_ch[channel].dmalock));
pr_debug("DMA CHANNEL IN USE \n"); pr_debug("DMA CHANNEL IN USE \n");
return -EBUSY; return -EBUSY;
} else {
dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
pr_debug("DMA CHANNEL IS ALLOCATED \n");
} }
mutex_unlock(&(dma_ch[channel].dmalock));
#ifdef CONFIG_BF54x #ifdef CONFIG_BF54x
if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
unsigned int per_map; unsigned int per_map;
...@@ -149,7 +139,7 @@ EXPORT_SYMBOL(request_dma); ...@@ -149,7 +139,7 @@ EXPORT_SYMBOL(request_dma);
int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data) int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data)
{ {
BUG_ON(channel >= MAX_DMA_CHANNELS || BUG_ON(channel >= MAX_DMA_CHANNELS ||
dma_ch[channel].chan_status == DMA_CHANNEL_FREE); !atomic_read(&dma_ch[channel].chan_status));
if (callback != NULL) { if (callback != NULL) {
int ret; int ret;
...@@ -184,7 +174,7 @@ void free_dma(unsigned int channel) ...@@ -184,7 +174,7 @@ void free_dma(unsigned int channel)
{ {
pr_debug("freedma() : BEGIN \n"); pr_debug("freedma() : BEGIN \n");
BUG_ON(channel >= MAX_DMA_CHANNELS || BUG_ON(channel >= MAX_DMA_CHANNELS ||
dma_ch[channel].chan_status == DMA_CHANNEL_FREE); !atomic_read(&dma_ch[channel].chan_status));
/* Halt the DMA */ /* Halt the DMA */
disable_dma(channel); disable_dma(channel);
...@@ -194,9 +184,7 @@ void free_dma(unsigned int channel) ...@@ -194,9 +184,7 @@ void free_dma(unsigned int channel)
free_irq(dma_ch[channel].irq, dma_ch[channel].data); free_irq(dma_ch[channel].irq, dma_ch[channel].data);
/* Clear the DMA Variable in the Channel */ /* Clear the DMA Variable in the Channel */
mutex_lock(&(dma_ch[channel].dmalock)); atomic_set(&dma_ch[channel].chan_status, 0);
dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
mutex_unlock(&(dma_ch[channel].dmalock));
pr_debug("freedma() : END \n"); pr_debug("freedma() : END \n");
} }
...@@ -210,13 +198,14 @@ int blackfin_dma_suspend(void) ...@@ -210,13 +198,14 @@ int blackfin_dma_suspend(void)
{ {
int i; int i;
for (i = 0; i < MAX_DMA_SUSPEND_CHANNELS; ++i) { for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
if (dma_ch[i].chan_status == DMA_CHANNEL_ENABLED) { if (dma_ch[i].regs->cfg & DMAEN) {
printk(KERN_ERR "DMA Channel %d failed to suspend\n", i); printk(KERN_ERR "DMA Channel %d failed to suspend\n", i);
return -EBUSY; return -EBUSY;
} }
dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map; if (i < MAX_DMA_SUSPEND_CHANNELS)
dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map;
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment