diff options
Diffstat (limited to 'arch/x86/lib/iomem.c')
-rw-r--r-- | arch/x86/lib/iomem.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/arch/x86/lib/iomem.c b/arch/x86/lib/iomem.c index 66894675f3c8..df50451d94ef 100644 --- a/arch/x86/lib/iomem.c +++ b/arch/x86/lib/iomem.c | |||
@@ -2,8 +2,11 @@ | |||
2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
3 | #include <linux/io.h> | 3 | #include <linux/io.h> |
4 | 4 | ||
5 | #define movs(type,to,from) \ | ||
6 | asm volatile("movs" type:"=&D" (to), "=&S" (from):"0" (to), "1" (from):"memory") | ||
7 | |||
5 | /* Originally from i386/string.h */ | 8 | /* Originally from i386/string.h */ |
6 | static __always_inline void __iomem_memcpy(void *to, const void *from, size_t n) | 9 | static __always_inline void rep_movs(void *to, const void *from, size_t n) |
7 | { | 10 | { |
8 | unsigned long d0, d1, d2; | 11 | unsigned long d0, d1, d2; |
9 | asm volatile("rep ; movsl\n\t" | 12 | asm volatile("rep ; movsl\n\t" |
@@ -21,13 +24,37 @@ static __always_inline void __iomem_memcpy(void *to, const void *from, size_t n) | |||
21 | 24 | ||
22 | void memcpy_fromio(void *to, const volatile void __iomem *from, size_t n) | 25 | void memcpy_fromio(void *to, const volatile void __iomem *from, size_t n) |
23 | { | 26 | { |
24 | __iomem_memcpy(to, (const void *)from, n); | 27 | if (unlikely(!n)) |
28 | return; | ||
29 | |||
30 | /* Align any unaligned source IO */ | ||
31 | if (unlikely(1 & (unsigned long)from)) { | ||
32 | movs("b", to, from); | ||
33 | n--; | ||
34 | } | ||
35 | if (n > 1 && unlikely(2 & (unsigned long)from)) { | ||
36 | movs("w", to, from); | ||
37 | n-=2; | ||
38 | } | ||
39 | rep_movs(to, (const void *)from, n); | ||
25 | } | 40 | } |
26 | EXPORT_SYMBOL(memcpy_fromio); | 41 | EXPORT_SYMBOL(memcpy_fromio); |
27 | 42 | ||
28 | void memcpy_toio(volatile void __iomem *to, const void *from, size_t n) | 43 | void memcpy_toio(volatile void __iomem *to, const void *from, size_t n) |
29 | { | 44 | { |
30 | __iomem_memcpy((void *)to, (const void *) from, n); | 45 | if (unlikely(!n)) |
46 | return; | ||
47 | |||
48 | /* Align any unaligned destination IO */ | ||
49 | if (unlikely(1 & (unsigned long)to)) { | ||
50 | movs("b", to, from); | ||
51 | n--; | ||
52 | } | ||
53 | if (n > 1 && unlikely(2 & (unsigned long)to)) { | ||
54 | movs("w", to, from); | ||
55 | n-=2; | ||
56 | } | ||
57 | rep_movs((void *)to, (const void *) from, n); | ||
31 | } | 58 | } |
32 | EXPORT_SYMBOL(memcpy_toio); | 59 | EXPORT_SYMBOL(memcpy_toio); |
33 | 60 | ||