linux/arch/microblaze/lib/memcpy.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
   3 * Copyright (C) 2008-2009 PetaLogix
   4 * Copyright (C) 2007 John Williams
   5 *
   6 * Reasonably optimised generic C-code for memcpy on Microblaze
   7 * This is generic C code to do efficient, alignment-aware memcpy.
   8 *
   9 * It is based on demo code originally Copyright 2001 by Intel Corp, taken from
  10 * http://www.embedded.com/showArticle.jhtml?articleID=19205567
  11 *
  12 * Attempts were made, unsuccessfully, to contact the original
  13 * author of this code (Michael Morrow, Intel).  Below is the original
  14 * copyright notice.
  15 *
  16 * This software has been developed by Intel Corporation.
  17 * Intel specifically disclaims all warranties, express or
  18 * implied, and all liability, including consequential and
  19 * other indirect damages, for the use of this program, including
  20 * liability for infringement of any proprietary rights,
  21 * and including the warranties of merchantability and fitness
  22 * for a particular purpose. Intel does not assume any
  23 * responsibility for and errors which may appear in this program
  24 * not any responsibility to update it.
  25 */
  26
  27#include <linux/export.h>
  28#include <linux/types.h>
  29#include <linux/stddef.h>
  30#include <linux/compiler.h>
  31
  32#include <linux/string.h>
  33
  34#ifdef __HAVE_ARCH_MEMCPY
  35#ifndef CONFIG_OPT_LIB_FUNCTION
  36void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
  37{
  38        const char *src = v_src;
  39        char *dst = v_dst;
  40
  41        /* Simple, byte oriented memcpy. */
  42        while (c--)
  43                *dst++ = *src++;
  44
  45        return v_dst;
  46}
  47#else /* CONFIG_OPT_LIB_FUNCTION */
  48void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
  49{
  50        const char *src = v_src;
  51        char *dst = v_dst;
  52
  53        /* The following code tries to optimize the copy by using unsigned
  54         * alignment. This will work fine if both source and destination are
  55         * aligned on the same boundary. However, if they are aligned on
  56         * different boundaries shifts will be necessary. This might result in
  57         * bad performance on MicroBlaze systems without a barrel shifter.
  58         */
  59        const uint32_t *i_src;
  60        uint32_t *i_dst;
  61
  62        if (likely(c >= 4)) {
  63                unsigned  value, buf_hold;
  64
  65                /* Align the destination to a word boundary. */
  66                /* This is done in an endian independent manner. */
  67                switch ((unsigned long)dst & 3) {
  68                case 1:
  69                        *dst++ = *src++;
  70                        --c;
  71                        fallthrough;
  72                case 2:
  73                        *dst++ = *src++;
  74                        --c;
  75                        fallthrough;
  76                case 3:
  77                        *dst++ = *src++;
  78                        --c;
  79                }
  80
  81                i_dst = (void *)dst;
  82
  83                /* Choose a copy scheme based on the source */
  84                /* alignment relative to destination. */
  85                switch ((unsigned long)src & 3) {
  86                case 0x0:       /* Both byte offsets are aligned */
  87                        i_src  = (const void *)src;
  88
  89                        for (; c >= 4; c -= 4)
  90                                *i_dst++ = *i_src++;
  91
  92                        src  = (const void *)i_src;
  93                        break;
  94                case 0x1:       /* Unaligned - Off by 1 */
  95                        /* Word align the source */
  96                        i_src = (const void *) ((unsigned)src & ~3);
  97#ifndef __MICROBLAZEEL__
  98                        /* Load the holding buffer */
  99                        buf_hold = *i_src++ << 8;
 100
 101                        for (; c >= 4; c -= 4) {
 102                                value = *i_src++;
 103                                *i_dst++ = buf_hold | value >> 24;
 104                                buf_hold = value << 8;
 105                        }
 106#else
 107                        /* Load the holding buffer */
 108                        buf_hold = (*i_src++ & 0xFFFFFF00) >> 8;
 109
 110                        for (; c >= 4; c -= 4) {
 111                                value = *i_src++;
 112                                *i_dst++ = buf_hold | ((value & 0xFF) << 24);
 113                                buf_hold = (value & 0xFFFFFF00) >> 8;
 114                        }
 115#endif
 116                        /* Realign the source */
 117                        src = (const void *)i_src;
 118                        src -= 3;
 119                        break;
 120                case 0x2:       /* Unaligned - Off by 2 */
 121                        /* Word align the source */
 122                        i_src = (const void *) ((unsigned)src & ~3);
 123#ifndef __MICROBLAZEEL__
 124                        /* Load the holding buffer */
 125                        buf_hold = *i_src++ << 16;
 126
 127                        for (; c >= 4; c -= 4) {
 128                                value = *i_src++;
 129                                *i_dst++ = buf_hold | value >> 16;
 130                                buf_hold = value << 16;
 131                        }
 132#else
 133                        /* Load the holding buffer */
 134                        buf_hold = (*i_src++ & 0xFFFF0000) >> 16;
 135
 136                        for (; c >= 4; c -= 4) {
 137                                value = *i_src++;
 138                                *i_dst++ = buf_hold | ((value & 0xFFFF) << 16);
 139                                buf_hold = (value & 0xFFFF0000) >> 16;
 140                        }
 141#endif
 142                        /* Realign the source */
 143                        src = (const void *)i_src;
 144                        src -= 2;
 145                        break;
 146                case 0x3:       /* Unaligned - Off by 3 */
 147                        /* Word align the source */
 148                        i_src = (const void *) ((unsigned)src & ~3);
 149#ifndef __MICROBLAZEEL__
 150                        /* Load the holding buffer */
 151                        buf_hold = *i_src++ << 24;
 152
 153                        for (; c >= 4; c -= 4) {
 154                                value = *i_src++;
 155                                *i_dst++ = buf_hold | value >> 8;
 156                                buf_hold = value << 24;
 157                        }
 158#else
 159                        /* Load the holding buffer */
 160                        buf_hold = (*i_src++ & 0xFF000000) >> 24;
 161
 162                        for (; c >= 4; c -= 4) {
 163                                value = *i_src++;
 164                                *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
 165                                buf_hold = (value & 0xFF000000) >> 24;
 166                        }
 167#endif
 168                        /* Realign the source */
 169                        src = (const void *)i_src;
 170                        src -= 1;
 171                        break;
 172                }
 173                dst = (void *)i_dst;
 174        }
 175
 176        /* Finish off any remaining bytes */
 177        /* simple fast copy, ... unless a cache boundary is crossed */
 178        switch (c) {
 179        case 3:
 180                *dst++ = *src++;
 181                fallthrough;
 182        case 2:
 183                *dst++ = *src++;
 184                fallthrough;
 185        case 1:
 186                *dst++ = *src++;
 187        }
 188
 189        return v_dst;
 190}
 191#endif /* CONFIG_OPT_LIB_FUNCTION */
 192EXPORT_SYMBOL(memcpy);
 193#endif /* __HAVE_ARCH_MEMCPY */
 194