[U-Boot] arm64: Add memcpy_{from, to}io() and memset_io() helpers
diff mbox series

Message ID 20191012105934.9518-1-vigneshr@ti.com
State Accepted
Delegated to: Tom Rini
Headers show
Series
  • [U-Boot] arm64: Add memcpy_{from, to}io() and memset_io() helpers
Related show

Commit Message

Vignesh Raghavendra Oct. 12, 2019, 10:59 a.m. UTC
Provide optimized memcpy_{from,to}io() and memset_io(). This is required
when moving large amount of data to and from IO regions such as IP
registers or accessing memory mapped flashes.

Code is borrowed from Linux Kernel v5.4.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
---
 arch/arm/include/asm/io.h | 104 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 101 insertions(+), 3 deletions(-)

Comments

Lokesh Vutla Oct. 15, 2019, 7:05 a.m. UTC | #1
On 12/10/19 4:29 PM, Vignesh Raghavendra wrote:
> Provide optimized memcpy_{from,to}io() and memset_io(). This is required
> when moving large amount of data to and from IO regions such as IP
> registers or accessing memory mapped flashes.
> 
> Code is borrowed from Linux Kernel v5.4.
> 
> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>

Reviewed-by: Lokesh Vutla <lokeshvutla@ti.com>

Thanks and regards,
Lokesh

> ---
>  arch/arm/include/asm/io.h | 104 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 101 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
> index e6d27b69f936..fcfb53f0d9d8 100644
> --- a/arch/arm/include/asm/io.h
> +++ b/arch/arm/include/asm/io.h
> @@ -23,6 +23,7 @@
>  #ifdef __KERNEL__
>  
>  #include <linux/types.h>
> +#include <linux/kernel.h>
>  #include <asm/byteorder.h>
>  #include <asm/memory.h>
>  #include <asm/barriers.h>
> @@ -315,6 +316,95 @@ extern void _memset_io(unsigned long, int, size_t);
>  
>  extern void __readwrite_bug(const char *fn);
>  
> +/* Optimized copy functions to read from/write to IO sapce */
> +#ifdef CONFIG_ARM64
> +/*
> + * Copy data from IO memory space to "real" memory space.
> + */
> +static inline
> +void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
> +{
> +	while (count && !IS_ALIGNED((unsigned long)from, 8)) {
> +		*(u8 *)to = __raw_readb(from);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +
> +	while (count >= 8) {
> +		*(u64 *)to = __raw_readq(from);
> +		from += 8;
> +		to += 8;
> +		count -= 8;
> +	}
> +
> +	while (count) {
> +		*(u8 *)to = __raw_readb(from);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +}
> +
> +/*
> + * Copy data from "real" memory space to IO memory space.
> + */
> +static inline
> +void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
> +{
> +	while (count && !IS_ALIGNED((unsigned long)to, 8)) {
> +		__raw_writeb(*(u8 *)from, to);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +
> +	while (count >= 8) {
> +		__raw_writeq(*(u64 *)from, to);
> +		from += 8;
> +		to += 8;
> +		count -= 8;
> +	}
> +
> +	while (count) {
> +		__raw_writeb(*(u8 *)from, to);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +}
> +
> +/*
> + * "memset" on IO memory space.
> + */
> +static inline
> +void __memset_io(volatile void __iomem *dst, int c, size_t count)
> +{
> +	u64 qc = (u8)c;
> +
> +	qc |= qc << 8;
> +	qc |= qc << 16;
> +	qc |= qc << 32;
> +
> +	while (count && !IS_ALIGNED((unsigned long)dst, 8)) {
> +		__raw_writeb(c, dst);
> +		dst++;
> +		count--;
> +	}
> +
> +	while (count >= 8) {
> +		__raw_writeq(qc, dst);
> +		dst += 8;
> +		count -= 8;
> +	}
> +
> +	while (count) {
> +		__raw_writeb(c, dst);
> +		dst++;
> +		count--;
> +	}
> +}
> +#endif /* CONFIG_ARM64 */
>  /*
>   * If this architecture has PCI memory IO, then define the read/write
>   * macros.  These should only be used with the cookie passed from
> @@ -355,9 +445,17 @@ out:
>  }
>  
>  #else
> -#define memset_io(a, b, c)		memset((void *)(a), (b), (c))
> -#define memcpy_fromio(a, b, c)		memcpy((a), (void *)(b), (c))
> -#define memcpy_toio(a, b, c)		memcpy((void *)(a), (b), (c))
> +
> +#ifdef CONFIG_ARM64
> +#define memset_io(a, b, c)		__memset_io((a), (b), (c))
> +#define memcpy_fromio(a, b, c)		__memcpy_fromio((a), (b), (c))
> +#define memcpy_toio(a, b, c)		__memcpy_toio((a), (b), (c))
> +#else
> +#define memset_io(a, b, c)             memset((void *)(a), (b), (c))
> +#define memcpy_fromio(a, b, c)         memcpy((a), (void *)(b), (c))
> +#define memcpy_toio(a, b, c)           memcpy((void *)(a), (b), (c))
> +#endif
> +
>  
>  #if !defined(readb)
>  
>
Tom Rini Nov. 8, 2019, 3:32 p.m. UTC | #2
On Sat, Oct 12, 2019 at 04:29:34PM +0530, Vignesh Raghavendra wrote:

> Provide optimized memcpy_{from,to}io() and memset_io(). This is required
> when moving large amount of data to and from IO regions such as IP
> registers or accessing memory mapped flashes.
> 
> Code is borrowed from Linux Kernel v5.4.
> 
> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
> Reviewed-by: Lokesh Vutla <lokeshvutla@ti.com>

Applied to u-boot/master, thanks!

Patch
diff mbox series

diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index e6d27b69f936..fcfb53f0d9d8 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -23,6 +23,7 @@ 
 #ifdef __KERNEL__
 
 #include <linux/types.h>
+#include <linux/kernel.h>
 #include <asm/byteorder.h>
 #include <asm/memory.h>
 #include <asm/barriers.h>
@@ -315,6 +316,95 @@  extern void _memset_io(unsigned long, int, size_t);
 
 extern void __readwrite_bug(const char *fn);
 
+/* Optimized copy functions to read from/write to IO sapce */
+#ifdef CONFIG_ARM64
+/*
+ * Copy data from IO memory space to "real" memory space.
+ */
+static inline
+void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
+{
+	while (count && !IS_ALIGNED((unsigned long)from, 8)) {
+		*(u8 *)to = __raw_readb(from);
+		from++;
+		to++;
+		count--;
+	}
+
+	while (count >= 8) {
+		*(u64 *)to = __raw_readq(from);
+		from += 8;
+		to += 8;
+		count -= 8;
+	}
+
+	while (count) {
+		*(u8 *)to = __raw_readb(from);
+		from++;
+		to++;
+		count--;
+	}
+}
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ */
+static inline
+void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
+{
+	while (count && !IS_ALIGNED((unsigned long)to, 8)) {
+		__raw_writeb(*(u8 *)from, to);
+		from++;
+		to++;
+		count--;
+	}
+
+	while (count >= 8) {
+		__raw_writeq(*(u64 *)from, to);
+		from += 8;
+		to += 8;
+		count -= 8;
+	}
+
+	while (count) {
+		__raw_writeb(*(u8 *)from, to);
+		from++;
+		to++;
+		count--;
+	}
+}
+
+/*
+ * "memset" on IO memory space.
+ */
+static inline
+void __memset_io(volatile void __iomem *dst, int c, size_t count)
+{
+	u64 qc = (u8)c;
+
+	qc |= qc << 8;
+	qc |= qc << 16;
+	qc |= qc << 32;
+
+	while (count && !IS_ALIGNED((unsigned long)dst, 8)) {
+		__raw_writeb(c, dst);
+		dst++;
+		count--;
+	}
+
+	while (count >= 8) {
+		__raw_writeq(qc, dst);
+		dst += 8;
+		count -= 8;
+	}
+
+	while (count) {
+		__raw_writeb(c, dst);
+		dst++;
+		count--;
+	}
+}
+#endif /* CONFIG_ARM64 */
 /*
  * If this architecture has PCI memory IO, then define the read/write
  * macros.  These should only be used with the cookie passed from
@@ -355,9 +445,17 @@  out:
 }
 
 #else
-#define memset_io(a, b, c)		memset((void *)(a), (b), (c))
-#define memcpy_fromio(a, b, c)		memcpy((a), (void *)(b), (c))
-#define memcpy_toio(a, b, c)		memcpy((void *)(a), (b), (c))
+
+#ifdef CONFIG_ARM64
+#define memset_io(a, b, c)		__memset_io((a), (b), (c))
+#define memcpy_fromio(a, b, c)		__memcpy_fromio((a), (b), (c))
+#define memcpy_toio(a, b, c)		__memcpy_toio((a), (b), (c))
+#else
+#define memset_io(a, b, c)             memset((void *)(a), (b), (c))
+#define memcpy_fromio(a, b, c)         memcpy((a), (void *)(b), (c))
+#define memcpy_toio(a, b, c)           memcpy((void *)(a), (b), (c))
+#endif
+
 
 #if !defined(readb)