linux/arch/mips/include/asm/checksum.h
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1995, 96, 97, 98, 99, 2001 by Ralf Baechle
   7 * Copyright (C) 1999 Silicon Graphics, Inc.
   8 * Copyright (C) 2001 Thiemo Seufer.
   9 * Copyright (C) 2002 Maciej W. Rozycki
  10 * Copyright (C) 2014 Imagination Technologies Ltd.
  11 */
  12#ifndef _ASM_CHECKSUM_H
  13#define _ASM_CHECKSUM_H
  14
  15#ifdef CONFIG_GENERIC_CSUM
  16#include <asm-generic/checksum.h>
  17#else
  18
  19#include <linux/in6.h>
  20
  21#include <linux/uaccess.h>
  22
  23/*
  24 * computes the checksum of a memory block at buff, length len,
  25 * and adds in "sum" (32-bit)
  26 *
  27 * returns a 32-bit number suitable for feeding into itself
  28 * or csum_tcpudp_magic
  29 *
  30 * this function must be called with even lengths, except
  31 * for the last fragment, which may be odd
  32 *
  33 * it's best to have buff aligned on a 32-bit boundary
  34 */
  35__wsum csum_partial(const void *buff, int len, __wsum sum);
  36
  37__wsum __csum_partial_copy_from_user(const void __user *src, void *dst, int len);
  38__wsum __csum_partial_copy_to_user(const void *src, void __user *dst, int len);
  39
  40#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
  41static inline
  42__wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
  43{
  44        might_fault();
  45        if (!access_ok(src, len))
  46                return 0;
  47        return __csum_partial_copy_from_user(src, dst, len);
  48}
  49
  50/*
  51 * Copy and checksum to user
  52 */
  53#define HAVE_CSUM_COPY_USER
  54static inline
  55__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len)
  56{
  57        might_fault();
  58        if (!access_ok(dst, len))
  59                return 0;
  60        return __csum_partial_copy_to_user(src, dst, len);
  61}
  62
  63/*
  64 * the same as csum_partial, but copies from user space (but on MIPS
  65 * we have just one address space, so this is identical to the above)
  66 */
  67#define _HAVE_ARCH_CSUM_AND_COPY
  68__wsum __csum_partial_copy_nocheck(const void *src, void *dst, int len);
  69static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
  70{
  71        return __csum_partial_copy_nocheck(src, dst, len);
  72}
  73
  74/*
  75 *      Fold a partial checksum without adding pseudo headers
  76 */
  77static inline __sum16 csum_fold(__wsum csum)
  78{
  79        u32 sum = (__force u32)csum;
  80
  81        sum += (sum << 16);
  82        csum = (__force __wsum)(sum < (__force u32)csum);
  83        sum >>= 16;
  84        sum += (__force u32)csum;
  85
  86        return (__force __sum16)~sum;
  87}
  88#define csum_fold csum_fold
  89
  90/*
  91 *      This is a version of ip_compute_csum() optimized for IP headers,
  92 *      which always checksum on 4 octet boundaries.
  93 *
  94 *      By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
  95 *      Arnt Gulbrandsen.
  96 */
  97static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
  98{
  99        const unsigned int *word = iph;
 100        const unsigned int *stop = word + ihl;
 101        unsigned int csum;
 102        int carry;
 103
 104        csum = word[0];
 105        csum += word[1];
 106        carry = (csum < word[1]);
 107        csum += carry;
 108
 109        csum += word[2];
 110        carry = (csum < word[2]);
 111        csum += carry;
 112
 113        csum += word[3];
 114        carry = (csum < word[3]);
 115        csum += carry;
 116
 117        word += 4;
 118        do {
 119                csum += *word;
 120                carry = (csum < *word);
 121                csum += carry;
 122                word++;
 123        } while (word != stop);
 124
 125        return csum_fold(csum);
 126}
 127#define ip_fast_csum ip_fast_csum
 128
 129static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
 130                                        __u32 len, __u8 proto,
 131                                        __wsum sum)
 132{
 133        __asm__(
 134        "       .set    push            # csum_tcpudp_nofold\n"
 135        "       .set    noat            \n"
 136#ifdef CONFIG_32BIT
 137        "       addu    %0, %2          \n"
 138        "       sltu    $1, %0, %2      \n"
 139        "       addu    %0, $1          \n"
 140
 141        "       addu    %0, %3          \n"
 142        "       sltu    $1, %0, %3      \n"
 143        "       addu    %0, $1          \n"
 144
 145        "       addu    %0, %4          \n"
 146        "       sltu    $1, %0, %4      \n"
 147        "       addu    %0, $1          \n"
 148#endif
 149#ifdef CONFIG_64BIT
 150        "       daddu   %0, %2          \n"
 151        "       daddu   %0, %3          \n"
 152        "       daddu   %0, %4          \n"
 153        "       dsll32  $1, %0, 0       \n"
 154        "       daddu   %0, $1          \n"
 155        "       sltu    $1, %0, $1      \n"
 156        "       dsra32  %0, %0, 0       \n"
 157        "       addu    %0, $1          \n"
 158#endif
 159        "       .set    pop"
 160        : "=r" (sum)
 161        : "0" ((__force unsigned long)daddr),
 162          "r" ((__force unsigned long)saddr),
 163#ifdef __MIPSEL__
 164          "r" ((proto + len) << 8),
 165#else
 166          "r" (proto + len),
 167#endif
 168          "r" ((__force unsigned long)sum));
 169
 170        return sum;
 171}
 172#define csum_tcpudp_nofold csum_tcpudp_nofold
 173
 174/*
 175 * this routine is used for miscellaneous IP-like checksums, mainly
 176 * in icmp.c
 177 */
 178static inline __sum16 ip_compute_csum(const void *buff, int len)
 179{
 180        return csum_fold(csum_partial(buff, len, 0));
 181}
 182
 183#define _HAVE_ARCH_IPV6_CSUM
 184static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
 185                                          const struct in6_addr *daddr,
 186                                          __u32 len, __u8 proto,
 187                                          __wsum sum)
 188{
 189        __wsum tmp;
 190
 191        __asm__(
 192        "       .set    push            # csum_ipv6_magic\n"
 193        "       .set    noreorder       \n"
 194        "       .set    noat            \n"
 195        "       addu    %0, %5          # proto (long in network byte order)\n"
 196        "       sltu    $1, %0, %5      \n"
 197        "       addu    %0, $1          \n"
 198
 199        "       addu    %0, %6          # csum\n"
 200        "       sltu    $1, %0, %6      \n"
 201        "       lw      %1, 0(%2)       # four words source address\n"
 202        "       addu    %0, $1          \n"
 203        "       addu    %0, %1          \n"
 204        "       sltu    $1, %0, %1      \n"
 205
 206        "       lw      %1, 4(%2)       \n"
 207        "       addu    %0, $1          \n"
 208        "       addu    %0, %1          \n"
 209        "       sltu    $1, %0, %1      \n"
 210
 211        "       lw      %1, 8(%2)       \n"
 212        "       addu    %0, $1          \n"
 213        "       addu    %0, %1          \n"
 214        "       sltu    $1, %0, %1      \n"
 215
 216        "       lw      %1, 12(%2)      \n"
 217        "       addu    %0, $1          \n"
 218        "       addu    %0, %1          \n"
 219        "       sltu    $1, %0, %1      \n"
 220
 221        "       lw      %1, 0(%3)       \n"
 222        "       addu    %0, $1          \n"
 223        "       addu    %0, %1          \n"
 224        "       sltu    $1, %0, %1      \n"
 225
 226        "       lw      %1, 4(%3)       \n"
 227        "       addu    %0, $1          \n"
 228        "       addu    %0, %1          \n"
 229        "       sltu    $1, %0, %1      \n"
 230
 231        "       lw      %1, 8(%3)       \n"
 232        "       addu    %0, $1          \n"
 233        "       addu    %0, %1          \n"
 234        "       sltu    $1, %0, %1      \n"
 235
 236        "       lw      %1, 12(%3)      \n"
 237        "       addu    %0, $1          \n"
 238        "       addu    %0, %1          \n"
 239        "       sltu    $1, %0, %1      \n"
 240
 241        "       addu    %0, $1          # Add final carry\n"
 242        "       .set    pop"
 243        : "=&r" (sum), "=&r" (tmp)
 244        : "r" (saddr), "r" (daddr),
 245          "0" (htonl(len)), "r" (htonl(proto)), "r" (sum));
 246
 247        return csum_fold(sum);
 248}
 249
 250#include <asm-generic/checksum.h>
 251#endif /* CONFIG_GENERIC_CSUM */
 252
 253#endif /* _ASM_CHECKSUM_H */
 254