[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