18c2ecf20Sopenharmony_ci#include <linux/string.h>
28c2ecf20Sopenharmony_ci#include <linux/module.h>
38c2ecf20Sopenharmony_ci#include <linux/io.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#define movs(type,to,from) \
68c2ecf20Sopenharmony_ci	asm volatile("movs" type:"=&D" (to), "=&S" (from):"0" (to), "1" (from):"memory")
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/* Originally from i386/string.h */
98c2ecf20Sopenharmony_cistatic __always_inline void rep_movs(void *to, const void *from, size_t n)
108c2ecf20Sopenharmony_ci{
118c2ecf20Sopenharmony_ci	unsigned long d0, d1, d2;
128c2ecf20Sopenharmony_ci	asm volatile("rep ; movsl\n\t"
138c2ecf20Sopenharmony_ci		     "testb $2,%b4\n\t"
148c2ecf20Sopenharmony_ci		     "je 1f\n\t"
158c2ecf20Sopenharmony_ci		     "movsw\n"
168c2ecf20Sopenharmony_ci		     "1:\ttestb $1,%b4\n\t"
178c2ecf20Sopenharmony_ci		     "je 2f\n\t"
188c2ecf20Sopenharmony_ci		     "movsb\n"
198c2ecf20Sopenharmony_ci		     "2:"
208c2ecf20Sopenharmony_ci		     : "=&c" (d0), "=&D" (d1), "=&S" (d2)
218c2ecf20Sopenharmony_ci		     : "0" (n / 4), "q" (n), "1" ((long)to), "2" ((long)from)
228c2ecf20Sopenharmony_ci		     : "memory");
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_civoid memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	if (unlikely(!n))
288c2ecf20Sopenharmony_ci		return;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* Align any unaligned source IO */
318c2ecf20Sopenharmony_ci	if (unlikely(1 & (unsigned long)from)) {
328c2ecf20Sopenharmony_ci		movs("b", to, from);
338c2ecf20Sopenharmony_ci		n--;
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci	if (n > 1 && unlikely(2 & (unsigned long)from)) {
368c2ecf20Sopenharmony_ci		movs("w", to, from);
378c2ecf20Sopenharmony_ci		n-=2;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci	rep_movs(to, (const void *)from, n);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memcpy_fromio);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_civoid memcpy_toio(volatile void __iomem *to, const void *from, size_t n)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	if (unlikely(!n))
468c2ecf20Sopenharmony_ci		return;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* Align any unaligned destination IO */
498c2ecf20Sopenharmony_ci	if (unlikely(1 & (unsigned long)to)) {
508c2ecf20Sopenharmony_ci		movs("b", to, from);
518c2ecf20Sopenharmony_ci		n--;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci	if (n > 1 && unlikely(2 & (unsigned long)to)) {
548c2ecf20Sopenharmony_ci		movs("w", to, from);
558c2ecf20Sopenharmony_ci		n-=2;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci	rep_movs((void *)to, (const void *) from, n);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memcpy_toio);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid memset_io(volatile void __iomem *a, int b, size_t c)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	/*
648c2ecf20Sopenharmony_ci	 * TODO: memset can mangle the IO patterns quite a bit.
658c2ecf20Sopenharmony_ci	 * perhaps it would be better to use a dumb one:
668c2ecf20Sopenharmony_ci	 */
678c2ecf20Sopenharmony_ci	memset((void *)a, b, c);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(memset_io);
70