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

Jonas Gorski jogo at openwrt.org
Mon Jul 21 13:47:26 PDT 2014


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 at openwrt.org>
---
 include/linux/mtd/map.h | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

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
-- 
2.0.0



More information about the linux-mtd mailing list