Blackfin arch: DMA operation cleanup
authorMichael Hennerich <michael.hennerich@analog.com>
Mon, 21 May 2007 10:09:17 +0000 (18:09 +0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 21 May 2007 16:50:22 +0000 (09:50 -0700)
1) Disable Interrupts during DMA memcpy to avoid raise conditions.
2) Mark MDMA channel 0 as reserved, since were using it internally.
3) Add DMA based equivalents for insX and outsX.
4) Our insX and outsX only handles len <= 2^16.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/blackfin/kernel/bfin_dma_5xx.c
include/asm-blackfin/io.h

index 14314240718e2f864c36ae26e22004278fb819ae..1c344acfd487adec434444d4f6eb74b8c53cfa1f 100644 (file)
@@ -130,7 +130,9 @@ static int __init blackfin_dma_init(void)
                dma_ch[i].regs = base_addr[i];
                mutex_init(&(dma_ch[i].dmalock));
        }
                dma_ch[i].regs = base_addr[i];
                mutex_init(&(dma_ch[i].dmalock));
        }
-
+       /* Mark MEMDMA Channel 0 as requested since we're using it internally */
+       dma_ch[CH_MEM_STREAM0_DEST].chan_status = DMA_CHANNEL_REQUESTED;
+       dma_ch[CH_MEM_STREAM0_SRC].chan_status = DMA_CHANNEL_REQUESTED;
        return 0;
 }
 
        return 0;
 }
 
@@ -598,9 +600,12 @@ void *dma_memcpy(void *dest, const void *src, size_t size)
        int direction;  /* 1 - address decrease, 0 - address increase */
        int flag_align; /* 1 - address aligned,  0 - address unaligned */
        int flag_2D;    /* 1 - 2D DMA needed,    0 - 1D DMA needed */
        int direction;  /* 1 - address decrease, 0 - address increase */
        int flag_align; /* 1 - address aligned,  0 - address unaligned */
        int flag_2D;    /* 1 - 2D DMA needed,    0 - 1D DMA needed */
+       unsigned long flags;
 
        if (size <= 0)
                return NULL;
 
        if (size <= 0)
                return NULL;
+       
+       local_irq_save(flags);
 
        if ((unsigned long)src < memory_end)
                blackfin_dcache_flush_range((unsigned int)src,
 
        if ((unsigned long)src < memory_end)
                blackfin_dcache_flush_range((unsigned int)src,
@@ -725,6 +730,7 @@ void *dma_memcpy(void *dest, const void *src, size_t size)
        if ((unsigned long)dest < memory_end)
                blackfin_dcache_invalidate_range((unsigned int)dest,
                                                 (unsigned int)(dest + size));
        if ((unsigned long)dest < memory_end)
                blackfin_dcache_invalidate_range((unsigned int)dest,
                                                 (unsigned int)(dest + size));
+       local_irq_restore(flags);
 
        return dest;
 }
 
        return dest;
 }
@@ -732,11 +738,201 @@ EXPORT_SYMBOL(dma_memcpy);
 
 void *safe_dma_memcpy(void *dest, const void *src, size_t size)
 {
 
 void *safe_dma_memcpy(void *dest, const void *src, size_t size)
 {
-       int flags = 0;
        void *addr;
        void *addr;
-       local_irq_save(flags);
        addr = dma_memcpy(dest, src, size);
        addr = dma_memcpy(dest, src, size);
-       local_irq_restore(flags);
        return addr;
 }
 EXPORT_SYMBOL(safe_dma_memcpy);
        return addr;
 }
 EXPORT_SYMBOL(safe_dma_memcpy);
+
+void dma_outsb(void __iomem *addr, const void *buf, unsigned short len)
+{
+
+       unsigned long flags;
+       
+       local_irq_save(flags);
+       
+       blackfin_dcache_flush_range((unsigned int)buf,(unsigned int)(buf) + len);
+
+       bfin_write_MDMA_D0_START_ADDR(addr);
+       bfin_write_MDMA_D0_X_COUNT(len);
+       bfin_write_MDMA_D0_X_MODIFY(0);
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_START_ADDR(buf);
+       bfin_write_MDMA_S0_X_COUNT(len);
+       bfin_write_MDMA_S0_X_MODIFY(1);
+       bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8);
+       bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8);
+
+       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE));
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(dma_outsb);
+
+
+void dma_insb(const void __iomem *addr, void *buf, unsigned short len)
+{
+       unsigned long flags;
+               
+       local_irq_save(flags);
+       bfin_write_MDMA_D0_START_ADDR(buf);
+       bfin_write_MDMA_D0_X_COUNT(len);
+       bfin_write_MDMA_D0_X_MODIFY(1);
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_START_ADDR(addr);
+       bfin_write_MDMA_S0_X_COUNT(len);
+       bfin_write_MDMA_S0_X_MODIFY(0);
+       bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8);
+       bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8);
+
+       blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len);
+
+       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE));
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(dma_insb);
+
+void dma_outsw(void __iomem *addr, const void  *buf, unsigned short len)
+{
+       unsigned long flags;
+       
+       local_irq_save(flags);
+               
+       blackfin_dcache_flush_range((unsigned int)buf,(unsigned int)(buf) + len);
+
+       bfin_write_MDMA_D0_START_ADDR(addr);
+       bfin_write_MDMA_D0_X_COUNT(len);
+       bfin_write_MDMA_D0_X_MODIFY(0);
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_START_ADDR(buf);
+       bfin_write_MDMA_S0_X_COUNT(len);
+       bfin_write_MDMA_S0_X_MODIFY(2);
+       bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
+       bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
+
+       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE));
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(dma_outsw);
+
+void dma_insw(const void __iomem *addr, void *buf, unsigned short len)
+{
+       unsigned long flags;
+               
+       local_irq_save(flags);
+       
+       bfin_write_MDMA_D0_START_ADDR(buf);
+       bfin_write_MDMA_D0_X_COUNT(len);
+       bfin_write_MDMA_D0_X_MODIFY(2);
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_START_ADDR(addr);
+       bfin_write_MDMA_S0_X_COUNT(len);
+       bfin_write_MDMA_S0_X_MODIFY(0);
+       bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
+       bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
+
+       blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len);
+
+       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE));
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(dma_insw);
+
+void dma_outsl(void __iomem *addr, const void *buf, unsigned short len)
+{
+       unsigned long flags;
+       
+       local_irq_save(flags);
+       
+       blackfin_dcache_flush_range((unsigned int)buf,(unsigned int)(buf) + len);
+
+       bfin_write_MDMA_D0_START_ADDR(addr);
+       bfin_write_MDMA_D0_X_COUNT(len);
+       bfin_write_MDMA_D0_X_MODIFY(0);
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_START_ADDR(buf);
+       bfin_write_MDMA_S0_X_COUNT(len);
+       bfin_write_MDMA_S0_X_MODIFY(4);
+       bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32);
+       bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32);
+
+       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE));
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(dma_outsl);
+
+void dma_insl(const void __iomem *addr, void *buf, unsigned short len)
+{
+       unsigned long flags;
+       
+       local_irq_save(flags);
+       
+       bfin_write_MDMA_D0_START_ADDR(buf);
+       bfin_write_MDMA_D0_X_COUNT(len);
+       bfin_write_MDMA_D0_X_MODIFY(4);
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_START_ADDR(addr);
+       bfin_write_MDMA_S0_X_COUNT(len);
+       bfin_write_MDMA_S0_X_MODIFY(0);
+       bfin_write_MDMA_S0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32);
+       bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32);
+
+       blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len);
+
+       while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE));
+
+       bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+       bfin_write_MDMA_S0_CONFIG(0);
+       bfin_write_MDMA_D0_CONFIG(0);
+       local_irq_restore(flags);
+
+}
+EXPORT_SYMBOL(dma_insl);
index 7e6995e80d97c7293bb18b2139c15971fe574f8f..eac8bcaf64c290dbaa259b5a874ca5b07d0f7a81 100644 (file)
@@ -115,13 +115,21 @@ static inline unsigned int readl(void __iomem *addr)
 
 #ifndef __ASSEMBLY__
 
 
 #ifndef __ASSEMBLY__
 
-extern void outsb(void __iomem *port, const void *addr, unsigned long count);
-extern void outsw(void __iomem *port, const void *addr, unsigned long count);
-extern void outsl(void __iomem *port, const void *addr, unsigned long count);
+extern void outsb(void __iomem *port, const void *addr, unsigned short count);
+extern void outsw(void __iomem *port, const void *addr, unsigned short count);
+extern void outsl(void __iomem *port, const void *addr, unsigned short count);
 
 
-extern void insb(const void __iomem *port, void *addr, unsigned long count);
-extern void insw(const void __iomem *port, void *addr, unsigned long count);
-extern void insl(const void __iomem *port, void *addr, unsigned long count);
+extern void insb(const void __iomem *port, void *addr, unsigned short count);
+extern void insw(const void __iomem *port, void *addr, unsigned short count);
+extern void insl(const void __iomem *port, void *addr, unsigned short count);
+
+extern void dma_outsb(void __iomem *port, const void *addr, unsigned short count);
+extern void dma_outsw(void __iomem *port, const void *addr, unsigned short count);
+extern void dma_outsl(void __iomem *port, const void *addr, unsigned short count);
+
+extern void dma_insb(const void __iomem *port, void *addr, unsigned short count);
+extern void dma_insw(const void __iomem *port, void *addr, unsigned short count);
+extern void dma_insl(const void __iomem *port, void *addr, unsigned short count);
 
 /*
  * Map some physical address range into the kernel address space.
 
 /*
  * Map some physical address range into the kernel address space.