/*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/export.h>27#include <linux/types.h>28#include <linux/stddef.h>29#include <linux/compiler.h>3031#include <linux/string.h>3233#ifdef CONFIG_OPT_LIB_FUNCTION34void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)35{36const char *src = v_src;37char *dst = v_dst;3839/* The following code tries to optimize the copy by using unsigned40* alignment. This will work fine if both source and destination are41* aligned on the same boundary. However, if they are aligned on42* different boundaries shifts will be necessary. This might result in43* bad performance on MicroBlaze systems without a barrel shifter.44*/45const uint32_t *i_src;46uint32_t *i_dst;4748if (likely(c >= 4)) {49unsigned value, buf_hold;5051/* Align the destination to a word boundary. */52/* This is done in an endian independent manner. */53switch ((unsigned long)dst & 3) {54case 1:55*dst++ = *src++;56--c;57fallthrough;58case 2:59*dst++ = *src++;60--c;61fallthrough;62case 3:63*dst++ = *src++;64--c;65}6667i_dst = (void *)dst;6869/* Choose a copy scheme based on the source */70/* alignment relative to destination. */71switch ((unsigned long)src & 3) {72case 0x0: /* Both byte offsets are aligned */73i_src = (const void *)src;7475for (; c >= 4; c -= 4)76*i_dst++ = *i_src++;7778src = (const void *)i_src;79break;80case 0x1: /* Unaligned - Off by 1 */81/* Word align the source */82i_src = (const void *) ((unsigned)src & ~3);83#ifndef __MICROBLAZEEL__84/* Load the holding buffer */85buf_hold = *i_src++ << 8;8687for (; c >= 4; c -= 4) {88value = *i_src++;89*i_dst++ = buf_hold | value >> 24;90buf_hold = value << 8;91}92#else93/* Load the holding buffer */94buf_hold = (*i_src++ & 0xFFFFFF00) >> 8;9596for (; c >= 4; c -= 4) {97value = *i_src++;98*i_dst++ = buf_hold | ((value & 0xFF) << 24);99buf_hold = (value & 0xFFFFFF00) >> 8;100}101#endif102/* Realign the source */103src = (const void *)i_src;104src -= 3;105break;106case 0x2: /* Unaligned - Off by 2 */107/* Word align the source */108i_src = (const void *) ((unsigned)src & ~3);109#ifndef __MICROBLAZEEL__110/* Load the holding buffer */111buf_hold = *i_src++ << 16;112113for (; c >= 4; c -= 4) {114value = *i_src++;115*i_dst++ = buf_hold | value >> 16;116buf_hold = value << 16;117}118#else119/* Load the holding buffer */120buf_hold = (*i_src++ & 0xFFFF0000) >> 16;121122for (; c >= 4; c -= 4) {123value = *i_src++;124*i_dst++ = buf_hold | ((value & 0xFFFF) << 16);125buf_hold = (value & 0xFFFF0000) >> 16;126}127#endif128/* Realign the source */129src = (const void *)i_src;130src -= 2;131break;132case 0x3: /* Unaligned - Off by 3 */133/* Word align the source */134i_src = (const void *) ((unsigned)src & ~3);135#ifndef __MICROBLAZEEL__136/* Load the holding buffer */137buf_hold = *i_src++ << 24;138139for (; c >= 4; c -= 4) {140value = *i_src++;141*i_dst++ = buf_hold | value >> 8;142buf_hold = value << 24;143}144#else145/* Load the holding buffer */146buf_hold = (*i_src++ & 0xFF000000) >> 24;147148for (; c >= 4; c -= 4) {149value = *i_src++;150*i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);151buf_hold = (value & 0xFF000000) >> 24;152}153#endif154/* Realign the source */155src = (const void *)i_src;156src -= 1;157break;158}159dst = (void *)i_dst;160}161162/* Finish off any remaining bytes */163/* simple fast copy, ... unless a cache boundary is crossed */164switch (c) {165case 3:166*dst++ = *src++;167fallthrough;168case 2:169*dst++ = *src++;170fallthrough;171case 1:172*dst++ = *src++;173}174175return v_dst;176}177EXPORT_SYMBOL(memcpy);178#endif /* CONFIG_OPT_LIB_FUNCTION */179180181