summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-05-13 15:29:02 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-05-14 10:30:41 +0000
commiteb0336ededda8d64b0f5fd98853b85ea5aa46060 (patch)
tree7570b0789ba8c2b6f85b2513b56a40d600af334c
parentff28d238b8a9dd5a5e457387378428ca8e3c8ffd (diff)
downloadrockbox-eb0336ededda8d64b0f5fd98853b85ea5aa46060.tar.gz
rockbox-eb0336ededda8d64b0f5fd98853b85ea5aa46060.tar.bz2
rockbox-eb0336ededda8d64b0f5fd98853b85ea5aa46060.zip
FAT: align writes when bounce buffering is enabled
Motivation: turns out the DMA in the M3K's MSC controller is buggy, and can't handle unaligned addresses properly despite the HW docs claiming otherwise. Extending the FAT driver bounce buffering code is the easiest way to work around the problem (but probably not the most efficient). Change-Id: I1b59b0eb4bbc881d317ff10c64ecadb1f9041236
-rw-r--r--firmware/drivers/fat.c57
1 files changed, 28 insertions, 29 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 50619983e9..337e29a1bc 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -2384,44 +2384,43 @@ static long transfer(struct bpb *fat_bpb, unsigned long start, long count,
panicf("Write %ld after data\n",
start + count - fat_bpb->totalsectors);
}
- else
- {
- rc = storage_write_sectors(IF_MD(fat_bpb->drive,)
- start + fat_bpb->startsector, count, buf);
- }
}
- else
- {
- void* xferbuf = buf;
-#ifdef STORAGE_NEEDS_BOUNCE_BUFFER
- int remain = count;
- int xferred = 0;
- int aligned = 1;
- if(STORAGE_OVERLAP((uintptr_t)buf)) {
- xferbuf = FAT_BOUNCE_BUFFER(fat_bpb);
- aligned = 0;
- count = MIN(remain, FAT_BOUNCE_SECTORS);
- }
- while(remain > 0) {
-#endif
- rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
- start + fat_bpb->startsector, count, xferbuf);
#ifdef STORAGE_NEEDS_BOUNCE_BUFFER
+ if(UNLIKELY(STORAGE_OVERLAP((uintptr_t)buf))) {
+ void* xfer_buf = FAT_BOUNCE_BUFFER(fat_bpb);
+ while(count > 0) {
+ int xfer_count = MIN(count, FAT_BOUNCE_SECTORS);
+
+ if(write) {
+ memcpy(xfer_buf, buf, xfer_count * SECTOR_SIZE);
+ rc = storage_write_sectors(IF_MD(fat_bpb->drive,)
+ start + fat_bpb->startsector, xfer_count, xfer_buf);
+ } else {
+ rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
+ start + fat_bpb->startsector, xfer_count, xfer_buf);
+ memcpy(buf, xfer_buf, xfer_count * SECTOR_SIZE);
+ }
+
if(rc < 0)
break;
- if(LIKELY(aligned))
- break;
- memcpy(buf, xferbuf, count * SECTOR_SIZE);
- buf += count * SECTOR_SIZE;
- xferred += count;
- start += count;
- remain -= count;
- count = MIN(remain, FAT_BOUNCE_SECTORS);
+ buf += xfer_count * SECTOR_SIZE;
+ start += xfer_count;
+ count -= xfer_count;
}
+ } else {
#endif
+ if(write) {
+ rc = storage_write_sectors(IF_MD(fat_bpb->drive,)
+ start + fat_bpb->startsector, count, buf);
+ } else {
+ rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
+ start + fat_bpb->startsector, count, buf);
+ }
+#ifdef STORAGE_NEEDS_BOUNCE_BUFFER
}
+#endif
if (rc < 0)
{