summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Ryabinin <ryabinin.a.a@gmail.com>2014-11-29 17:06:35 +0300
committerAndrew Ryabinin <ryabinin.a.a@gmail.com>2014-11-29 21:00:11 +0300
commit8618f2c227e7daed2d1dd566090c2c4588533470 (patch)
tree2225821258966d4076c00b1ee8afc9523f8c0d3e
parentd1fcfe950a70ddbdd97164832cdb83ef2cc7f23a (diff)
downloadrockbox-8618f2c.tar.gz
rockbox-8618f2c.zip
rk27xx: sd: properly align buffer used for DMA transfers.
Commit 7d1a47cf ("Rewrite filesystem code (WIP)") exposed bug in rk27xx sd driver. Buffer passed to sd_read/write_sectors() doesn't has to be cacheline aligned. DMA transfers on unaligned buffers is quiet dangerous thing. Make sure that the buffer is aligned to cacheline size, If not use a temporary aligned buffer for DMA transfer. Change-Id: I91420f2b8d58159c80c3f15f4b35e88ea0dfd14c
-rw-r--r--firmware/target/arm/rk27xx/sd-rk27xx.c27
-rw-r--r--firmware/target/arm/rk27xx/system-target.h2
2 files changed, 25 insertions, 4 deletions
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c
index 9d6821ee38..6eeff7bae5 100644
--- a/firmware/target/arm/rk27xx/sd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/sd-rk27xx.c
@@ -58,6 +58,8 @@ static tCardInfo card_info;
static long last_disk_activity = -1;
static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)];
+static unsigned char aligned_buf[512] STORAGE_ALIGN_ATTR;
+
static const char sd_thread_name[] = "ata/sd";
static struct mutex sd_mtx SHAREDBSS_ATTR;
static struct event_queue sd_queue;
@@ -460,9 +462,15 @@ int sd_init(void)
static inline void read_sd_data(unsigned char **dst)
{
- commit_discard_dcache_range((const void *)*dst, 512);
+ void *buf = *dst;
+
+ if (!IS_ALIGNED(((unsigned long)*dst), CACHEALIGN_SIZE))
+ buf = aligned_buf;
+
+ commit_discard_dcache_range((const void *)buf, 512);
- A2A_IDST0 = (unsigned long)*dst;
+
+ A2A_IDST0 = (unsigned long)buf;
A2A_CON0 = (3<<9) | /* burst 16 */
(1<<6) | /* fixed src */
(1<<3) | /* DMA start */
@@ -472,14 +480,25 @@ static inline void read_sd_data(unsigned char **dst)
/* wait for DMA engine to finish transfer */
while (A2A_DMA_STS & 1);
+ if (buf == aligned_buf)
+ memcpy(*dst, aligned_buf, 512);
+
*dst += 512;
}
static inline void write_sd_data(unsigned char **src)
{
- commit_discard_dcache_range((const void *)*src, 512);
+ void *buf = *src;
+
+ if (!IS_ALIGNED(((unsigned long)*src), CACHEALIGN_SIZE))
+ {
+ buf = aligned_buf;
+ memcpy(aligned_buf, *src, 512);
+ }
+
+ commit_discard_dcache_range((const void *)buf, 512);
- A2A_ISRC1 = (unsigned long)*src;
+ A2A_ISRC1 = (unsigned long)buf;
A2A_CON1 = (3<<9) | /* burst 16 */
(1<<5) | /* fixed dst */
(1<<3) | /* DMA start */
diff --git a/firmware/target/arm/rk27xx/system-target.h b/firmware/target/arm/rk27xx/system-target.h
index 8a705dd77a..a5b27cc6b2 100644
--- a/firmware/target/arm/rk27xx/system-target.h
+++ b/firmware/target/arm/rk27xx/system-target.h
@@ -52,4 +52,6 @@ void commit_discard_idcache(void);
#define CPUFREQ_NORMAL 50000000
#define CPUFREQ_MAX 200000000
+#define STORAGE_WANTS_ALIGN
+
#endif /* SYSTEM_TARGET_H */