Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / arch / microblaze / lib / memmove.c
index 0929198..123e361 100644 (file)
 #include <linux/string.h>
 
 #ifdef __HAVE_ARCH_MEMMOVE
+#ifndef CONFIG_OPT_LIB_FUNCTION
 void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
 {
        const char *src = v_src;
        char *dst = v_dst;
 
-#ifdef CONFIG_OPT_LIB_FUNCTION
-       const uint32_t *i_src;
-       uint32_t *i_dst;
-#endif
-
        if (!c)
                return v_dst;
 
@@ -48,7 +44,6 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
        if (v_dst <= v_src)
                return memcpy(v_dst, v_src, c);
 
-#ifndef CONFIG_OPT_LIB_FUNCTION
        /* copy backwards, from end to beginning */
        src += c;
        dst += c;
@@ -58,7 +53,22 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                *--dst = *--src;
 
        return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+       const char *src = v_src;
+       char *dst = v_dst;
+       const uint32_t *i_src;
+       uint32_t *i_dst;
+
+       if (!c)
+               return v_dst;
+
+       /* Use memcpy when source is higher than dest */
+       if (v_dst <= v_src)
+               return memcpy(v_dst, v_src, c);
+
        /* The following code tries to optimize the copy by using unsigned
         * alignment. This will work fine if both source and destination are
         * aligned on the same boundary. However, if they are aligned on
@@ -104,7 +114,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x1:       /* Unaligned - Off by 1 */
                        /* Word align the source */
                        i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *--i_src >> 24;
 
@@ -113,7 +123,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                                *--i_dst = buf_hold << 8 | value;
                                buf_hold = value >> 24;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*--i_src & 0xFF) << 24;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *--i_src;
+                               *--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8);
+                               buf_hold = (value  & 0xFF) << 24;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src += 1;
@@ -121,7 +140,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x2:       /* Unaligned - Off by 2 */
                        /* Word align the source */
                        i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *--i_src >> 16;
 
@@ -130,7 +149,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                                *--i_dst = buf_hold << 16 | value;
                                buf_hold = value >> 16;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*--i_src & 0xFFFF) << 16;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *--i_src;
+                               *--i_dst = buf_hold | ((value & 0xFFFF0000)>>16);
+                               buf_hold = (value & 0xFFFF) << 16;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src += 2;
@@ -138,7 +166,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                case 0x3:       /* Unaligned - Off by 3 */
                        /* Word align the source */
                        i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
                        /* Load the holding buffer */
                        buf_hold = *--i_src >> 8;
 
@@ -147,7 +175,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                                *--i_dst = buf_hold << 24 | value;
                                buf_hold = value >> 8;
                        }
+#else
+                       /* Load the holding buffer */
+                       buf_hold = (*--i_src & 0xFFFFFF) << 8;
 
+                       for (; c >= 4; c -= 4) {
+                               value = *--i_src;
+                               *--i_dst = buf_hold | ((value & 0xFF000000)>> 24);
+                               buf_hold = (value & 0xFFFFFF) << 8;;
+                       }
+#endif
                        /* Realign the source */
                        src = (const void *)i_src;
                        src += 3;
@@ -169,7 +206,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
                *--dst = *--src;
        }
        return v_dst;
-#endif
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memmove);
 #endif /* __HAVE_ARCH_MEMMOVE */