Various architectures have almost the same implementations for memcpy_{to,from}io and memset_io functions. So, consolidate them into the existing lib/iomap_copy.c. Reviewed-by: Yann Sionneau <ysionneau@xxxxxxxxxxxxx> Signed-off-by: Julian Vetter <jvetter@xxxxxxxxxxxxx> --- Changes for v8: - Replaced shifts by 'qc *= ~0UL / 0xff' - Modification in v6.12-rc2: Include 'linux/unaligned.h' instead of 'asm/unaligned.h' --- include/asm-generic/io.h | 58 ++---------------- lib/iomap_copy.c | 127 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 52 deletions(-) diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 80de699bf6af..f14655ed4d9d 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -102,6 +102,12 @@ static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __i #endif /* CONFIG_TRACE_MMIO_ACCESS */ +extern void memcpy_fromio(void *to, const volatile void __iomem *from, + size_t count); +extern void memcpy_toio(volatile void __iomem *to, const void *from, + size_t count); +extern void memset_io(volatile void __iomem *dst, int c, size_t count); + /* * __raw_{read,write}{b,w,l,q}() access memory in native endianness. * @@ -1150,58 +1156,6 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) } #endif -#ifndef memset_io -#define memset_io memset_io -/** - * memset_io Set a range of I/O memory to a constant value - * @addr: The beginning of the I/O-memory range to set - * @val: The value to set the memory to - * @count: The number of bytes to set - * - * Set a range of I/O memory to a given value. - */ -static inline void memset_io(volatile void __iomem *addr, int value, - size_t size) -{ - memset(__io_virt(addr), value, size); -} -#endif - -#ifndef memcpy_fromio -#define memcpy_fromio memcpy_fromio -/** - * memcpy_fromio Copy a block of data from I/O memory - * @dst: The (RAM) destination for the copy - * @src: The (I/O memory) source for the data - * @count: The number of bytes to copy - * - * Copy a block of data from I/O memory. - */ -static inline void memcpy_fromio(void *buffer, - const volatile void __iomem *addr, - size_t size) -{ - memcpy(buffer, __io_virt(addr), size); -} -#endif - -#ifndef memcpy_toio -#define memcpy_toio memcpy_toio -/** - * memcpy_toio Copy a block of data into I/O memory - * @dst: The (I/O memory) destination for the copy - * @src: The (RAM) source for the data - * @count: The number of bytes to copy - * - * Copy a block of data to I/O memory. - */ -static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer, - size_t size) -{ - memcpy(__io_virt(addr), buffer, size); -} -#endif - extern int devmem_is_allowed(unsigned long pfn); #endif /* __KERNEL__ */ diff --git a/lib/iomap_copy.c b/lib/iomap_copy.c index 2fd5712fb7c0..175d6930c293 100644 --- a/lib/iomap_copy.c +++ b/lib/iomap_copy.c @@ -3,8 +3,11 @@ * Copyright 2006 PathScale, Inc. All Rights Reserved. */ +#include <linux/align.h> #include <linux/export.h> #include <linux/io.h> +#include <linux/types.h> +#include <linux/unaligned.h> /** * __iowrite32_copy - copy data to MMIO space, in 32-bit units @@ -76,3 +79,127 @@ void __iowrite64_copy(void __iomem *to, const void *from, size_t count) } EXPORT_SYMBOL_GPL(__iowrite64_copy); #endif + +#ifndef memcpy_fromio +/** + * memcpy_fromio Copy a block of data from I/O memory + * @to: The (RAM) destination for the copy + * @from: The (I/O memory) source for the data + * @count: The number of bytes to copy + * + * Copy a block of data from I/O memory. + */ +void memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) +{ + while (count && !IS_ALIGNED((long)from, sizeof(long))) { + *(u8 *)to = __raw_readb(from); + from++; + to++; + count--; + } + + while (count >= sizeof(long)) { +#ifdef CONFIG_64BIT + long val = __raw_readq(from); +#else + long val = __raw_readl(from); +#endif + put_unaligned(val, (long *)to); + + + from += sizeof(long); + to += sizeof(long); + count -= sizeof(long); + } + + while (count) { + *(u8 *)to = __raw_readb(from); + from++; + to++; + count--; + } +} +EXPORT_SYMBOL(memcpy_fromio); +#endif + +#ifndef memcpy_toio +/** + * memcpy_toio Copy a block of data into I/O memory + * @to: The (I/O memory) destination for the copy + * @from: The (RAM) source for the data + * @count: The number of bytes to copy + * + * Copy a block of data to I/O memory. + */ +void memcpy_toio(volatile void __iomem *to, const void *from, size_t count) +{ + while (count && !IS_ALIGNED((long)to, sizeof(long))) { + __raw_writeb(*(u8 *)from, to); + from++; + to++; + count--; + } + + while (count >= sizeof(long)) { + long val = get_unaligned((long *)from); +#ifdef CONFIG_64BIT + __raw_writeq(val, to); +#else + __raw_writel(val, to); +#endif + + from += sizeof(long); + to += sizeof(long); + count -= sizeof(long); + } + + while (count) { + __raw_writeb(*(u8 *)from, to); + from++; + to++; + count--; + } +} +EXPORT_SYMBOL(memcpy_toio); +#endif + +#ifndef memset_io +/** + * memset_io Set a range of I/O memory to a constant value + * @dst: The beginning of the I/O-memory range to set + * @c: The value to set the memory to + * @count: The number of bytes to set + * + * Set a range of I/O memory to a given value. + */ +void memset_io(volatile void __iomem *dst, int c, size_t count) +{ + long qc = (u8)c; + + qc *= ~0UL / 0xff; + + while (count && !IS_ALIGNED((long)dst, sizeof(long))) { + __raw_writeb(c, dst); + dst++; + count--; + } + + while (count >= sizeof(long)) { +#ifdef CONFIG_64BIT + __raw_writeq(qc, dst); +#else + __raw_writel(qc, dst); +#endif + + dst += sizeof(long); + count -= sizeof(long); + } + + while (count) { + __raw_writeb(c, dst); + dst++; + count--; + } +} +EXPORT_SYMBOL(memset_io); +#endif -- 2.34.1