summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2009-04-10 17:03:56 +0000
committerThomas Martitz <kugel@rockbox.org>2009-04-10 17:03:56 +0000
commitec797ed62225a5f78f37e9342ac6e183332f795b (patch)
tree4e108d0a88f85abcc3c558382f0ae55ec9f329fc /firmware/target
parentbac611868e499aadf58bfcc3a64e5c80eecf40bd (diff)
downloadrockbox-ec797ed62225a5f78f37e9342ac6e183332f795b.tar.gz
rockbox-ec797ed62225a5f78f37e9342ac6e183332f795b.zip
FS#10113 - Sansa AMS : do not use unaligned buffers on ATA DMA by Rafaël Carré.
Fixes various storage related problems like stuttering audio, md5sum and test disk failure and Sansa Fuze's backdrop corruption by using aligned buffers. There's a speed penalty but stability has more priority. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20679 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/as3525/ata_sd_as3525.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c
index 042af3b5a1..7e5bc126af 100644
--- a/firmware/target/arm/as3525/ata_sd_as3525.c
+++ b/firmware/target/arm/as3525/ata_sd_as3525.c
@@ -645,14 +645,18 @@ static int sd_select_bank(signed char bank)
645 return 0; 645 return 0;
646} 646}
647 647
648#define UNALIGNED_NUM_SECTORS 10
649static int32_t aligned_buffer[UNALIGNED_NUM_SECTORS* (SECTOR_SIZE / 4)];
650
648static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, 651static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
649 int count, void* buf, bool write) 652 int count, void* buf, const bool write)
650{ 653{
651#ifndef HAVE_MULTIVOLUME 654#ifndef HAVE_MULTIVOLUME
652 const int drive = 0; 655 const int drive = 0;
653#endif 656#endif
654 int ret = 0; 657 int ret = 0;
655 int bank; 658 int bank;
659 bool unaligned_transfer = (int)buf & 3;
656 660
657 /* skip SanDisk OF */ 661 /* skip SanDisk OF */
658 if (drive == INTERNAL_AS3525) 662 if (drive == INTERNAL_AS3525)
@@ -706,17 +710,30 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
706 710
707 while(count) 711 while(count)
708 { 712 {
709 /* Interrupt handler might set this to true during transfer */
710 retry = false;
711 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH 713 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH
712 * register, so we have to transfer maximum 127 sectors at a time. */ 714 * register, so we have to transfer maximum 127 sectors at a time. */
713 unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */ 715 unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */
716 void *dma_buf;
714 const int cmd = 717 const int cmd =
715 write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK; 718 write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
716 int arg = start; 719 int arg = start;
717 if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */ 720 if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */
718 arg *= BLOCK_SIZE; 721 arg *= BLOCK_SIZE;
719 722
723 /* Interrupt handler might set this to true during transfer */
724 retry = false;
725
726 if(unaligned_transfer)
727 {
728 dma_buf = aligned_buffer;
729 if(transfer > UNALIGNED_NUM_SECTORS)
730 transfer = UNALIGNED_NUM_SECTORS;
731 if(write)
732 memcpy(aligned_buffer, buf, transfer * SECTOR_SIZE);
733 }
734 else
735 dma_buf = buf;
736
720 if(!send_cmd(drive, cmd, arg, MCI_ARG, NULL)) 737 if(!send_cmd(drive, cmd, arg, MCI_ARG, NULL))
721 { 738 {
722 ret -= 3*20; 739 ret -= 3*20;
@@ -724,11 +741,11 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
724 } 741 }
725 742
726 if(write) 743 if(write)
727 dma_enable_channel(0, buf, MCI_FIFO(drive), 744 dma_enable_channel(0, dma_buf, MCI_FIFO(drive),
728 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, 745 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
729 DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); 746 DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
730 else 747 else
731 dma_enable_channel(0, MCI_FIFO(drive), buf, 748 dma_enable_channel(0, MCI_FIFO(drive), dma_buf,
732 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, 749 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
733 DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); 750 DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL);
734 751
@@ -743,6 +760,8 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
743 wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK); 760 wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK);
744 if(!retry) 761 if(!retry)
745 { 762 {
763 if(unaligned_transfer && !write)
764 memcpy(buf, aligned_buffer, transfer * SECTOR_SIZE);
746 buf += transfer * SECTOR_SIZE; 765 buf += transfer * SECTOR_SIZE;
747 start += transfer; 766 start += transfer;
748 count -= transfer; 767 count -= transfer;