linux/arch/tile/lib/checksum.c
<<
>>
Prefs
   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