diff options
| author | Mike Frysinger <vapier@gentoo.org> | 2009-06-29 18:45:50 -0400 |
|---|---|---|
| committer | Mike Frysinger <vapier@gentoo.org> | 2009-07-16 01:52:26 -0400 |
| commit | 532f07ca04c6f8ab0555b00cf5d42dc6f72b802f (patch) | |
| tree | 6a449019028efc5518da6abd3e18437ca60ade6c | |
| parent | fb4b5d3a379824d94fd71fc1aa78e9dbcb15b948 (diff) | |
Blackfin: fix early_dma_memcpy() handling of busy channels
The early logic to locate a free DMA channel and then set it up was broken
in a few ways that only manifested itself when we needed to set up more
than 2 on chip SRAM regions (most board defaults setup 1 or 2). First, we
checked the wrong status register (the destination gets updated, not the
source) and second, we did the ssync before rather than after resetting a
DMA config register.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
| -rw-r--r-- | arch/blackfin/kernel/bfin_dma_5xx.c | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index e0bf8cc06907..9f9b82816652 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c | |||
| @@ -253,32 +253,31 @@ void __init early_dma_memcpy(void *pdst, const void *psrc, size_t size) | |||
| 253 | BUG_ON(src % 4); | 253 | BUG_ON(src % 4); |
| 254 | BUG_ON(size % 4); | 254 | BUG_ON(size % 4); |
| 255 | 255 | ||
| 256 | /* Force a sync in case a previous config reset on this channel | ||
| 257 | * occurred. This is needed so subsequent writes to DMA registers | ||
| 258 | * are not spuriously lost/corrupted. | ||
| 259 | */ | ||
| 260 | __builtin_bfin_ssync(); | ||
| 261 | |||
| 262 | src_ch = 0; | 256 | src_ch = 0; |
| 263 | /* Find an avalible memDMA channel */ | 257 | /* Find an avalible memDMA channel */ |
| 264 | while (1) { | 258 | while (1) { |
| 265 | if (!src_ch || src_ch == (struct dma_register *)MDMA_S1_NEXT_DESC_PTR) { | 259 | if (src_ch == (struct dma_register *)MDMA_S0_NEXT_DESC_PTR) { |
| 266 | dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR; | ||
| 267 | src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR; | ||
| 268 | } else { | ||
| 269 | dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR; | 260 | dst_ch = (struct dma_register *)MDMA_D1_NEXT_DESC_PTR; |
| 270 | src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR; | 261 | src_ch = (struct dma_register *)MDMA_S1_NEXT_DESC_PTR; |
| 262 | } else { | ||
| 263 | dst_ch = (struct dma_register *)MDMA_D0_NEXT_DESC_PTR; | ||
| 264 | src_ch = (struct dma_register *)MDMA_S0_NEXT_DESC_PTR; | ||
| 271 | } | 265 | } |
| 272 | 266 | ||
| 273 | if (!bfin_read16(&src_ch->cfg)) { | 267 | if (!bfin_read16(&src_ch->cfg)) |
| 268 | break; | ||
| 269 | else if (bfin_read16(&dst_ch->irq_status) & DMA_DONE) { | ||
| 270 | bfin_write16(&src_ch->cfg, 0); | ||
| 274 | break; | 271 | break; |
| 275 | } else { | ||
| 276 | if (bfin_read16(&src_ch->irq_status) & DMA_DONE) | ||
| 277 | bfin_write16(&src_ch->cfg, 0); | ||
| 278 | } | 272 | } |
| 279 | |||
| 280 | } | 273 | } |
| 281 | 274 | ||
| 275 | /* Force a sync in case a previous config reset on this channel | ||
| 276 | * occurred. This is needed so subsequent writes to DMA registers | ||
| 277 | * are not spuriously lost/corrupted. | ||
| 278 | */ | ||
| 279 | __builtin_bfin_ssync(); | ||
| 280 | |||
| 282 | /* Destination */ | 281 | /* Destination */ |
| 283 | bfin_write32(&dst_ch->start_addr, dst); | 282 | bfin_write32(&dst_ch->start_addr, dst); |
| 284 | bfin_write16(&dst_ch->x_count, size >> 2); | 283 | bfin_write16(&dst_ch->x_count, size >> 2); |
