diff mbox

[1/3] mtd: simple_map: make NO_XIP actually prevent unaligned accesses

Message ID 1405975648-25375-2-git-send-email-jogo@openwrt.org
State Changes Requested
Headers show

Commit Message

Jonas Gorski July 21, 2014, 8:47 p.m. UTC
Some mapping drivers set the map->phys pointer to NO_XIP intending to
mean "no unaligned accesses" (see also the DT property of physmap_of).
But simple mapping read_from/write_to still just call memcpy, which will
do unaligned reads/writes at least on mips.

To work around this, make the inline version check for NO_XIP and do a byte
wise copy if "to" or "from" is unaligned.

Signed-off-by: Jonas Gorski <jogo@openwrt.org>
---
 include/linux/mtd/map.h | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 5f487d7..92a8a0a 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -435,15 +435,35 @@  static inline void inline_map_write(struct map_info *map, const map_word datum,
 
 static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
-	if (map->cached)
+	if (map->cached) {
 		memcpy(to, (char *)map->cached + from, len);
-	else
+	} else if (map->phys != NO_XIP ||
+		   (IS_ALIGNED((unsigned long)to, sizeof(long)) &&
+		    IS_ALIGNED((unsigned long)map->virt + from,
+			       sizeof(long)))) {
 		memcpy_fromio(to, map->virt + from, len);
+	} else {
+		void __iomem *src = map->virt + from;
+		char *dst = (char *)to;
+
+		while (len--)
+			*dst++ = readb(src++);
+	}
 }
 
 static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
-	memcpy_toio(map->virt + to, from, len);
+	if (map->phys != NO_XIP ||
+	    (IS_ALIGNED((unsigned long)map->virt + to, sizeof(long)) &&
+	     IS_ALIGNED((unsigned long)from, sizeof(long)))) {
+		memcpy_toio(map->virt + to, from, len);
+	} else {
+		char *src = (char *)from;
+		void __iomem *dst = map->virt + to;
+
+		while (len--)
+			writeb(*src++, dst++);
+	}
 }
 
 #ifdef CONFIG_MTD_COMPLEX_MAPPINGS