From 1a7d91d651f25005c4f507aebf9eab17e508889c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 10 Oct 2007 17:42:55 +0800 Subject: Blackfin arch: flush/inv the correct range when using write back cache and fix bugs find by dmacopy - flush/inv the correct range - dmacopy test failed when policy is write_back - invalidate before dma http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3367 It's the cache invalidate what is causing the issue. There is no invalidate only instruction it's always: FLUSHINV So when we "invalidate" after the DMA we might (do) overwrite freshly dma'ed data by dirty Cache WB content. Fixed by moving the "invalidate" at the beginning of dma_memcpy. Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_dma_5xx.c | 39 ++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) (limited to 'arch/blackfin') diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 17edd6599959..e19164fb4cd1 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -436,6 +436,10 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) blackfin_dcache_flush_range((unsigned int)src, (unsigned int)(src + size)); + if ((unsigned long)dest < memory_end) + blackfin_dcache_invalidate_range((unsigned int)dest, + (unsigned int)(dest + size)); + bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); if ((unsigned long)src < (unsigned long)dest) @@ -543,6 +547,8 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) } } + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ; @@ -552,9 +558,6 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) bfin_write_MDMA_S0_CONFIG(0); bfin_write_MDMA_D0_CONFIG(0); - if ((unsigned long)dest < memory_end) - blackfin_dcache_invalidate_range((unsigned int)dest, - (unsigned int)(dest + size)); local_irq_restore(flags); return dest; @@ -589,7 +592,8 @@ void dma_outsb(unsigned long addr, const void *buf, unsigned short len) local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + 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); @@ -604,6 +608,8 @@ void dma_outsb(unsigned long addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -620,6 +626,9 @@ void dma_insb(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); bfin_write_MDMA_D0_X_COUNT(len); @@ -634,7 +643,7 @@ void dma_insb(unsigned long addr, void *buf, unsigned short len) 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); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); @@ -653,7 +662,8 @@ void dma_outsw(unsigned long addr, const void *buf, unsigned short len) local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(short)); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -668,6 +678,8 @@ void dma_outsw(unsigned long addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -683,6 +695,9 @@ void dma_insw(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(short)); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); @@ -698,7 +713,7 @@ void dma_insw(unsigned long addr, void *buf, unsigned short len) 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); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); @@ -717,7 +732,8 @@ void dma_outsl(unsigned long addr, const void *buf, unsigned short len) local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(long)); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -732,6 +748,8 @@ void dma_outsl(unsigned long addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -747,6 +765,9 @@ void dma_insl(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(long)); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); @@ -762,7 +783,7 @@ void dma_insl(unsigned long addr, void *buf, unsigned short len) 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); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); -- cgit v1.2.3-59-g8ed1b