/*1* Copyright (C) 2008-2009 Michal Simek <[email protected]>2* Copyright (C) 2008-2009 PetaLogix3* Copyright (C) 2007 John Williams4*5* Reasonably optimised generic C-code for memcpy on Microblaze6* This is generic C code to do efficient, alignment-aware memcpy.7*8* It is based on demo code originally Copyright 2001 by Intel Corp, taken from9* http://www.embedded.com/showArticle.jhtml?articleID=1920556710*11* Attempts were made, unsuccessfully, to contact the original12* author of this code (Michael Morrow, Intel). Below is the original13* copyright notice.14*15* This software has been developed by Intel Corporation.16* Intel specifically disclaims all warranties, express or17* implied, and all liability, including consequential and18* other indirect damages, for the use of this program, including19* liability for infringement of any proprietary rights,20* and including the warranties of merchantability and fitness21* for a particular purpose. Intel does not assume any22* responsibility for and errors which may appear in this program23* not any responsibility to update it.24*/2526#include <linux/types.h>27#include <linux/stddef.h>28#include <linux/compiler.h>29#include <linux/module.h>3031#include <linux/string.h>32#include <asm/system.h>3334#ifdef __HAVE_ARCH_MEMCPY35#ifndef CONFIG_OPT_LIB_FUNCTION36void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)37{38const char *src = v_src;39char *dst = v_dst;4041/* Simple, byte oriented memcpy. */42while (c--)43*dst++ = *src++;4445return v_dst;46}47#else /* CONFIG_OPT_LIB_FUNCTION */48void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)49{50const char *src = v_src;51char *dst = v_dst;5253/* The following code tries to optimize the copy by using unsigned54* alignment. This will work fine if both source and destination are55* aligned on the same boundary. However, if they are aligned on56* different boundaries shifts will be necessary. This might result in57* bad performance on MicroBlaze systems without a barrel shifter.58*/59const uint32_t *i_src;60uint32_t *i_dst;6162if (likely(c >= 4)) {63unsigned value, buf_hold;6465/* Align the destination to a word boundary. */66/* This is done in an endian independent manner. */67switch ((unsigned long)dst & 3) {68case 1:69*dst++ = *src++;70--c;71case 2:72*dst++ = *src++;73--c;74case 3:75*dst++ = *src++;76--c;77}7879i_dst = (void *)dst;8081/* Choose a copy scheme based on the source */82/* alignment relative to destination. */83switch ((unsigned long)src & 3) {84case 0x0: /* Both byte offsets are aligned */85i_src = (const void *)src;8687for (; c >= 4; c -= 4)88*i_dst++ = *i_src++;8990src = (const void *)i_src;91break;92case 0x1: /* Unaligned - Off by 1 */93/* Word align the source */94i_src = (const void *) ((unsigned)src & ~3);95#ifndef __MICROBLAZEEL__96/* Load the holding buffer */97buf_hold = *i_src++ << 8;9899for (; c >= 4; c -= 4) {100value = *i_src++;101*i_dst++ = buf_hold | value >> 24;102buf_hold = value << 8;103}104#else105/* Load the holding buffer */106buf_hold = (*i_src++ & 0xFFFFFF00) >>8;107108for (; c >= 4; c -= 4) {109value = *i_src++;110*i_dst++ = buf_hold | ((value & 0xFF) << 24);111buf_hold = (value & 0xFFFFFF00) >>8;112}113#endif114/* Realign the source */115src = (const void *)i_src;116src -= 3;117break;118case 0x2: /* Unaligned - Off by 2 */119/* Word align the source */120i_src = (const void *) ((unsigned)src & ~3);121#ifndef __MICROBLAZEEL__122/* Load the holding buffer */123buf_hold = *i_src++ << 16;124125for (; c >= 4; c -= 4) {126value = *i_src++;127*i_dst++ = buf_hold | value >> 16;128buf_hold = value << 16;129}130#else131/* Load the holding buffer */132buf_hold = (*i_src++ & 0xFFFF0000 )>>16;133134for (; c >= 4; c -= 4) {135value = *i_src++;136*i_dst++ = buf_hold | ((value & 0xFFFF)<<16);137buf_hold = (value & 0xFFFF0000) >>16;138}139#endif140/* Realign the source */141src = (const void *)i_src;142src -= 2;143break;144case 0x3: /* Unaligned - Off by 3 */145/* Word align the source */146i_src = (const void *) ((unsigned)src & ~3);147#ifndef __MICROBLAZEEL__148/* Load the holding buffer */149buf_hold = *i_src++ << 24;150151for (; c >= 4; c -= 4) {152value = *i_src++;153*i_dst++ = buf_hold | value >> 8;154buf_hold = value << 24;155}156#else157/* Load the holding buffer */158buf_hold = (*i_src++ & 0xFF000000) >> 24;159160for (; c >= 4; c -= 4) {161value = *i_src++;162*i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);163buf_hold = (value & 0xFF000000) >> 24;164}165#endif166/* Realign the source */167src = (const void *)i_src;168src -= 1;169break;170}171dst = (void *)i_dst;172}173174/* Finish off any remaining bytes */175/* simple fast copy, ... unless a cache boundary is crossed */176switch (c) {177case 3:178*dst++ = *src++;179case 2:180*dst++ = *src++;181case 1:182*dst++ = *src++;183}184185return v_dst;186}187#endif /* CONFIG_OPT_LIB_FUNCTION */188EXPORT_SYMBOL(memcpy);189#endif /* __HAVE_ARCH_MEMCPY */190191192