@@ -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
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(-)