summaryrefslogtreecommitdiff
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-8618f2c227e7daed2d1dd566090c2c4588533470.tar.gz
rockbox-8618f2c227e7daed2d1dd566090c2c4588533470.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;
58static long last_disk_activity = -1; 58static long last_disk_activity = -1;
59 59
60static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)]; 60static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x200)/sizeof(long)];
61static unsigned char aligned_buf[512] STORAGE_ALIGN_ATTR;
62
61static const char sd_thread_name[] = "ata/sd"; 63static const char sd_thread_name[] = "ata/sd";
62static struct mutex sd_mtx SHAREDBSS_ATTR; 64static struct mutex sd_mtx SHAREDBSS_ATTR;
63static struct event_queue sd_queue; 65static struct event_queue sd_queue;
@@ -460,9 +462,15 @@ int sd_init(void)
460 462
461static inline void read_sd_data(unsigned char **dst) 463static inline void read_sd_data(unsigned char **dst)
462{ 464{
463 commit_discard_dcache_range((const void *)*dst, 512); 465 void *buf = *dst;
466
467 if (!IS_ALIGNED(((unsigned long)*dst), CACHEALIGN_SIZE))
468 buf = aligned_buf;
469
470 commit_discard_dcache_range((const void *)buf, 512);
464 471
465 A2A_IDST0 = (unsigned long)*dst; 472
473 A2A_IDST0 = (unsigned long)buf;
466 A2A_CON0 = (3<<9) | /* burst 16 */ 474 A2A_CON0 = (3<<9) | /* burst 16 */
467 (1<<6) | /* fixed src */ 475 (1<<6) | /* fixed src */
468 (1<<3) | /* DMA start */ 476 (1<<3) | /* DMA start */
@@ -472,14 +480,25 @@ static inline void read_sd_data(unsigned char **dst)
472 /* wait for DMA engine to finish transfer */ 480 /* wait for DMA engine to finish transfer */
473 while (A2A_DMA_STS & 1); 481 while (A2A_DMA_STS & 1);
474 482
483 if (buf == aligned_buf)
484 memcpy(*dst, aligned_buf, 512);
485
475 *dst += 512; 486 *dst += 512;
476} 487}
477 488
478static inline void write_sd_data(unsigned char **src) 489static inline void write_sd_data(unsigned char **src)
479{ 490{
480 commit_discard_dcache_range((const void *)*src, 512); 491 void *buf = *src;
492
493 if (!IS_ALIGNED(((unsigned long)*src), CACHEALIGN_SIZE))
494 {
495 buf = aligned_buf;
496 memcpy(aligned_buf, *src, 512);
497 }
498
499 commit_discard_dcache_range((const void *)buf, 512);
481 500
482 A2A_ISRC1 = (unsigned long)*src; 501 A2A_ISRC1 = (unsigned long)buf;
483 A2A_CON1 = (3<<9) | /* burst 16 */ 502 A2A_CON1 = (3<<9) | /* burst 16 */
484 (1<<5) | /* fixed dst */ 503 (1<<5) | /* fixed dst */
485 (1<<3) | /* DMA start */ 504 (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);
52#define CPUFREQ_NORMAL 50000000 52#define CPUFREQ_NORMAL 50000000
53#define CPUFREQ_MAX 200000000 53#define CPUFREQ_MAX 200000000
54 54
55#define STORAGE_WANTS_ALIGN
56
55#endif /* SYSTEM_TARGET_H */ 57#endif /* SYSTEM_TARGET_H */