/* * 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> static inline unsigned int longto16(unsigned long x) { unsigned long ret; #ifdef __tilegx__ ret = __insn_v2sadu(x, 0); ret = __insn_v2sadu(ret, 0); #else ret = __insn_sadh_u(x, 0); ret = __insn_sadh_u(ret, 0); #endif return ret; } __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; result = longto16(result); if (odd) result = swab16(result); out: return result; }