Skip to content

Commit

Permalink
Blackfin: convert DMA mutex to an atomic and drop redundant code
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mike Frysinger committed Dec 15, 2009
1 parent adfc046 commit d2e015d
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 35 deletions.
17 changes: 3 additions & 14 deletions arch/blackfin/include/asm/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <linux/interrupt.h>
#include <mach/dma.h>
#include <asm/atomic.h>
#include <asm/blackfin.h>
#include <asm/page.h>

Expand All @@ -19,11 +20,6 @@
* Generic DMA Declarations
*
****************************************************************************/
enum dma_chan_status {
DMA_CHANNEL_FREE,
DMA_CHANNEL_REQUESTED,
DMA_CHANNEL_ENABLED,
};

/*-------------------------
* config reg bits value
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
31 changes: 10 additions & 21 deletions arch/blackfin/kernel/bfin_dma_5xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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");
}
Expand All @@ -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;
Expand Down

0 comments on commit d2e015d

Please sign in to comment.