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