diff options
author | Thomas Martitz <kugel@rockbox.org> | 2009-04-10 17:03:56 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2009-04-10 17:03:56 +0000 |
commit | ec797ed62225a5f78f37e9342ac6e183332f795b (patch) | |
tree | 4e108d0a88f85abcc3c558382f0ae55ec9f329fc /firmware/target/arm/as3525/ata_sd_as3525.c | |
parent | bac611868e499aadf58bfcc3a64e5c80eecf40bd (diff) | |
download | rockbox-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/arm/as3525/ata_sd_as3525.c')
-rw-r--r-- | firmware/target/arm/as3525/ata_sd_as3525.c | 29 |
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 | ||
649 | static int32_t aligned_buffer[UNALIGNED_NUM_SECTORS* (SECTOR_SIZE / 4)]; | ||
650 | |||
648 | static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, | 651 | static 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; |