mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
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:
parent
adfc046740
commit
d2e015d65f
2 changed files with 13 additions and 35 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue