From 8618f2c227e7daed2d1dd566090c2c4588533470 Mon Sep 17 00:00:00 2001 From: Andrew Ryabinin Date: Sat, 29 Nov 2014 17:06:35 +0300 Subject: 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 --- firmware/target/arm/rk27xx/sd-rk27xx.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'firmware/target/arm/rk27xx/sd-rk27xx.c') 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 */ -- cgit v1.2.3