2009-03-27 16:25:21 +03:00
/*
* Copyright ( C ) 2008 - 2009 Michal Simek < monstr @ monstr . eu >
* Copyright ( C ) 2008 - 2009 PetaLogix
* Copyright ( C ) 2007 John Williams
*
* Reasonably optimised generic C - code for memcpy on Microblaze
* This is generic C code to do efficient , alignment - aware memmove .
*
* It is based on demo code originally Copyright 2001 by Intel Corp , taken from
* http : //www.embedded.com/showArticle.jhtml?articleID=19205567
*
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 18:09:05 +03:00
* Attempts were made , unsuccessfully , to contact the original
2009-03-27 16:25:21 +03:00
* author of this code ( Michael Morrow , Intel ) . Below is the original
* copyright notice .
*
* This software has been developed by Intel Corporation .
* Intel specifically disclaims all warranties , express or
* implied , and all liability , including consequential and
* other indirect damages , for the use of this program , including
* liability for infringement of any proprietary rights ,
* and including the warranties of merchantability and fitness
* for a particular purpose . Intel does not assume any
* responsibility for and errors which may appear in this program
* not any responsibility to update it .
*/
# include <linux/types.h>
# include <linux/stddef.h>
# include <linux/compiler.h>
# include <linux/module.h>
# include <linux/string.h>
# ifdef __HAVE_ARCH_MEMMOVE
2010-10-09 07:58:24 +04:00
# ifndef CONFIG_OPT_LIB_FUNCTION
2009-03-27 16:25:21 +03:00
void * memmove ( void * v_dst , const void * v_src , __kernel_size_t c )
{
const char * src = v_src ;
char * dst = v_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 ) ;
/* copy backwards, from end to beginning */
src + = c ;
dst + = c ;
/* Simple, byte oriented memmove. */
while ( c - - )
* - - dst = * - - src ;
return v_dst ;
2010-10-09 07:58:24 +04:00
}
# 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 ) ;
2009-03-27 16:25:21 +03:00
/* 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
* different boundaries shifts will be necessary . This might result in
* bad performance on MicroBlaze systems without a barrel shifter .
*/
/* FIXME this part needs more test */
/* Do a descending copy - this is a bit trickier! */
dst + = c ;
src + = c ;
if ( c > = 4 ) {
unsigned value , buf_hold ;
2011-03-31 05:57:33 +04:00
/* Align the destination to a word boundary. */
/* This is done in an endian independent manner. */
2009-03-27 16:25:21 +03:00
switch ( ( unsigned long ) dst & 3 ) {
case 3 :
* - - dst = * - - src ;
- - c ;
case 2 :
* - - dst = * - - src ;
- - c ;
case 1 :
* - - dst = * - - src ;
- - c ;
}
i_dst = ( void * ) dst ;
/* Choose a copy scheme based on the source */
/* alignment relative to dstination. */
switch ( ( unsigned long ) src & 3 ) {
case 0x0 : /* Both byte offsets are aligned */
i_src = ( const void * ) src ;
for ( ; c > = 4 ; c - = 4 )
* - - i_dst = * - - i_src ;
src = ( const void * ) i_src ;
break ;
case 0x1 : /* Unaligned - Off by 1 */
/* Word align the source */
i_src = ( const void * ) ( ( ( unsigned ) src + 4 ) & ~ 3 ) ;
2010-10-09 08:05:58 +04:00
# ifndef __MICROBLAZEEL__
2009-03-27 16:25:21 +03:00
/* Load the holding buffer */
buf_hold = * - - i_src > > 24 ;
for ( ; c > = 4 ; c - = 4 ) {
value = * - - i_src ;
* - - i_dst = buf_hold < < 8 | value ;
buf_hold = value > > 24 ;
}
2010-10-09 08:05:58 +04:00
# else
/* Load the holding buffer */
buf_hold = ( * - - i_src & 0xFF ) < < 24 ;
2009-03-27 16:25:21 +03:00
2010-10-09 08:05:58 +04:00
for ( ; c > = 4 ; c - = 4 ) {
value = * - - i_src ;
* - - i_dst = buf_hold | ( ( value & 0xFFFFFF00 ) > > 8 ) ;
buf_hold = ( value & 0xFF ) < < 24 ;
}
# endif
2009-03-27 16:25:21 +03:00
/* Realign the source */
src = ( const void * ) i_src ;
src + = 1 ;
break ;
case 0x2 : /* Unaligned - Off by 2 */
/* Word align the source */
i_src = ( const void * ) ( ( ( unsigned ) src + 4 ) & ~ 3 ) ;
2010-10-09 08:05:58 +04:00
# ifndef __MICROBLAZEEL__
2009-03-27 16:25:21 +03:00
/* Load the holding buffer */
buf_hold = * - - i_src > > 16 ;
for ( ; c > = 4 ; c - = 4 ) {
value = * - - i_src ;
* - - i_dst = buf_hold < < 16 | value ;
buf_hold = value > > 16 ;
}
2010-10-09 08:05:58 +04:00
# else
/* Load the holding buffer */
buf_hold = ( * - - i_src & 0xFFFF ) < < 16 ;
2009-03-27 16:25:21 +03:00
2010-10-09 08:05:58 +04:00
for ( ; c > = 4 ; c - = 4 ) {
value = * - - i_src ;
* - - i_dst = buf_hold | ( ( value & 0xFFFF0000 ) > > 16 ) ;
buf_hold = ( value & 0xFFFF ) < < 16 ;
}
# endif
2009-03-27 16:25:21 +03:00
/* Realign the source */
src = ( const void * ) i_src ;
src + = 2 ;
break ;
case 0x3 : /* Unaligned - Off by 3 */
/* Word align the source */
i_src = ( const void * ) ( ( ( unsigned ) src + 4 ) & ~ 3 ) ;
2010-10-09 08:05:58 +04:00
# ifndef __MICROBLAZEEL__
2009-03-27 16:25:21 +03:00
/* Load the holding buffer */
buf_hold = * - - i_src > > 8 ;
for ( ; c > = 4 ; c - = 4 ) {
value = * - - i_src ;
* - - i_dst = buf_hold < < 24 | value ;
buf_hold = value > > 8 ;
}
2010-10-09 08:05:58 +04:00
# else
/* Load the holding buffer */
buf_hold = ( * - - i_src & 0xFFFFFF ) < < 8 ;
2009-03-27 16:25:21 +03:00
2010-10-09 08:05:58 +04:00
for ( ; c > = 4 ; c - = 4 ) {
value = * - - i_src ;
* - - i_dst = buf_hold | ( ( value & 0xFF000000 ) > > 24 ) ;
2010-11-15 06:04:21 +03:00
buf_hold = ( value & 0xFFFFFF ) < < 8 ;
2010-10-09 08:05:58 +04:00
}
# endif
2009-03-27 16:25:21 +03:00
/* Realign the source */
src = ( const void * ) i_src ;
src + = 3 ;
break ;
}
dst = ( void * ) i_dst ;
}
2011-03-31 05:57:33 +04:00
/* simple fast copy, ... unless a cache boundary is crossed */
2009-03-27 16:25:21 +03:00
/* Finish off any remaining bytes */
switch ( c ) {
case 4 :
* - - dst = * - - src ;
case 3 :
* - - dst = * - - src ;
case 2 :
* - - dst = * - - src ;
case 1 :
* - - dst = * - - src ;
}
return v_dst ;
}
2010-10-09 07:58:24 +04:00
# endif /* CONFIG_OPT_LIB_FUNCTION */
2009-03-27 16:25:21 +03:00
EXPORT_SYMBOL ( memmove ) ;
# endif /* __HAVE_ARCH_MEMMOVE */