1/* 2 * Copyright 2010 Tilera Corporation. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 11 * NON INFRINGEMENT. See the GNU General Public License for 12 * more details. 13 * Support code for the main lib/checksum.c. 14 */ 15 16#include <net/checksum.h> 17#include <linux/module.h> 18 19static inline unsigned int longto16(unsigned long x) 20{ 21 unsigned long ret; 22#ifdef __tilegx__ 23 ret = __insn_v2sadu(x, 0); 24 ret = __insn_v2sadu(ret, 0); 25#else 26 ret = __insn_sadh_u(x, 0); 27 ret = __insn_sadh_u(ret, 0); 28#endif 29 return ret; 30} 31 32__wsum do_csum(const unsigned char *buff, int len) 33{ 34 int odd, count; 35 unsigned long result = 0; 36 37 if (len <= 0) 38 goto out; 39 odd = 1 & (unsigned long) buff; 40 if (odd) { 41 result = (*buff << 8); 42 len--; 43 buff++; 44 } 45 count = len >> 1; /* nr of 16-bit words.. */ 46 if (count) { 47 if (2 & (unsigned long) buff) { 48 result += *(const unsigned short *)buff; 49 count--; 50 len -= 2; 51 buff += 2; 52 } 53 count >>= 1; /* nr of 32-bit words.. */ 54 if (count) { 55#ifdef __tilegx__ 56 if (4 & (unsigned long) buff) { 57 unsigned int w = *(const unsigned int *)buff; 58 result = __insn_v2sadau(result, w, 0); 59 count--; 60 len -= 4; 61 buff += 4; 62 } 63 count >>= 1; /* nr of 64-bit words.. */ 64#endif 65 66 /* 67 * This algorithm could wrap around for very 68 * large buffers, but those should be impossible. 69 */ 70 BUG_ON(count >= 65530); 71 72 while (count) { 73 unsigned long w = *(const unsigned long *)buff; 74 count--; 75 buff += sizeof(w); 76#ifdef __tilegx__ 77 result = __insn_v2sadau(result, w, 0); 78#else 79 result = __insn_sadah_u(result, w, 0); 80#endif 81 } 82#ifdef __tilegx__ 83 if (len & 4) { 84 unsigned int w = *(const unsigned int *)buff; 85 result = __insn_v2sadau(result, w, 0); 86 buff += 4; 87 } 88#endif 89 } 90 if (len & 2) { 91 result += *(const unsigned short *) buff; 92 buff += 2; 93 } 94 } 95 if (len & 1) 96 result += *buff; 97 result = longto16(result); 98 if (odd) 99 result = swab16(result); 100out: 101 return result; 102} 103