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>
This commit is contained in:
Mike Frysinger 2009-10-09 22:18:12 +00:00
parent adfc046740
commit d2e015d65f
2 changed files with 13 additions and 35 deletions

View File

@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <mach/dma.h>
#include <asm/atomic.h>
#include <asm/blackfin.h>
#include <asm/page.h>
@ -19,11 +20,6 @@
* Generic DMA Declarations
*
****************************************************************************/
enum dma_chan_status {
DMA_CHANNEL_FREE,
DMA_CHANNEL_REQUESTED,
DMA_CHANNEL_ENABLED,
};
/*-------------------------
* config reg bits value
@ -104,11 +100,9 @@ struct dma_register {
};
struct mutex;
struct dma_channel {
struct mutex dmalock;
const char *device_id;
enum dma_chan_status chan_status;
atomic_t chan_status;
volatile struct dma_register *regs;
struct dmasg *sg; /* large mode descriptor */
unsigned int irq;
@ -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)
{
if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE)
return 0;
else
return 1;
return atomic_read(&dma_ch[channel].chan_status);
}
static inline void disable_dma(unsigned int channel)
{
dma_ch[channel].regs->cfg &= ~DMAEN;
SSYNC();
dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
}
static inline void enable_dma(unsigned int channel)
{
dma_ch[channel].regs->curr_x_count = 0;
dma_ch[channel].regs->curr_y_count = 0;
dma_ch[channel].regs->cfg |= DMAEN;
dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
}
void free_dma(unsigned int channel);
int request_dma(unsigned int channel, const char *device_id);

View File

@ -37,9 +37,8 @@ static int __init blackfin_dma_init(void)
printk(KERN_INFO "Blackfin DMA Controller\n");
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];
mutex_init(&(dma_ch[i].dmalock));
}
/* Mark MEMDMA Channel 0 as requested since we're using it internally */
request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy");
@ -60,7 +59,7 @@ static int proc_dma_show(struct seq_file *m, void *v)
int 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);
return 0;
@ -107,20 +106,11 @@ int request_dma(unsigned int channel, const char *device_id)
}
#endif
mutex_lock(&(dma_ch[channel].dmalock));
if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
|| (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
mutex_unlock(&(dma_ch[channel].dmalock));
if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) {
pr_debug("DMA CHANNEL IN USE \n");
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
if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
unsigned int per_map;
@ -149,7 +139,7 @@ EXPORT_SYMBOL(request_dma);
int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data)
{
BUG_ON(channel >= MAX_DMA_CHANNELS ||
dma_ch[channel].chan_status == DMA_CHANNEL_FREE);
!atomic_read(&dma_ch[channel].chan_status));
if (callback != NULL) {
int ret;
@ -184,7 +174,7 @@ void free_dma(unsigned int channel)
{
pr_debug("freedma() : BEGIN \n");
BUG_ON(channel >= MAX_DMA_CHANNELS ||
dma_ch[channel].chan_status == DMA_CHANNEL_FREE);
!atomic_read(&dma_ch[channel].chan_status));
/* Halt the DMA */
disable_dma(channel);
@ -194,9 +184,7 @@ void free_dma(unsigned int channel)
free_irq(dma_ch[channel].irq, dma_ch[channel].data);
/* Clear the DMA Variable in the Channel */
mutex_lock(&(dma_ch[channel].dmalock));
dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
mutex_unlock(&(dma_ch[channel].dmalock));
atomic_set(&dma_ch[channel].chan_status, 0);
pr_debug("freedma() : END \n");
}
@ -210,13 +198,14 @@ int blackfin_dma_suspend(void)
{
int i;
for (i = 0; i < MAX_DMA_SUSPEND_CHANNELS; ++i) {
if (dma_ch[i].chan_status == DMA_CHANNEL_ENABLED) {
for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
if (dma_ch[i].regs->cfg & DMAEN) {
printk(KERN_ERR "DMA Channel %d failed to suspend\n", i);
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;