2010-05-28 23:09:12 -04:00
/*
* Copyright 2010 Tilera Corporation . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation , version 2.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for
* more details .
* Support code for the main lib / checksum . c .
*/
# include <net/checksum.h>
# include <linux/module.h>
__wsum do_csum ( const unsigned char * buff , int len )
{
int odd , count ;
unsigned long result = 0 ;
if ( len < = 0 )
goto out ;
odd = 1 & ( unsigned long ) buff ;
if ( odd ) {
result = ( * buff < < 8 ) ;
len - - ;
buff + + ;
}
count = len > > 1 ; /* nr of 16-bit words.. */
if ( count ) {
if ( 2 & ( unsigned long ) buff ) {
result + = * ( const unsigned short * ) buff ;
count - - ;
len - = 2 ;
buff + = 2 ;
}
count > > = 1 ; /* nr of 32-bit words.. */
if ( count ) {
# ifdef __tilegx__
if ( 4 & ( unsigned long ) buff ) {
unsigned int w = * ( const unsigned int * ) buff ;
result = __insn_v2sadau ( result , w , 0 ) ;
count - - ;
len - = 4 ;
buff + = 4 ;
}
count > > = 1 ; /* nr of 64-bit words.. */
# endif
/*
* This algorithm could wrap around for very
* large buffers , but those should be impossible .
*/
BUG_ON ( count > = 65530 ) ;
while ( count ) {
unsigned long w = * ( const unsigned long * ) buff ;
count - - ;
buff + = sizeof ( w ) ;
# ifdef __tilegx__
result = __insn_v2sadau ( result , w , 0 ) ;
# else
result = __insn_sadah_u ( result , w , 0 ) ;
# endif
}
# ifdef __tilegx__
if ( len & 4 ) {
unsigned int w = * ( const unsigned int * ) buff ;
result = __insn_v2sadau ( result , w , 0 ) ;
buff + = 4 ;
}
# endif
}
if ( len & 2 ) {
result + = * ( const unsigned short * ) buff ;
buff + = 2 ;
}
}
if ( len & 1 )
result + = * buff ;
2012-04-28 15:41:39 -04:00
result = csum_long ( result ) ;
2010-05-28 23:09:12 -04:00
if ( odd )
result = swab16 ( result ) ;
out :
return result ;
}