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        unsigned long tmp = (__force unsigned long)sum;
 134
 135        __asm__(
 136        "       .set    push            # csum_tcpudp_nofold\n"
 137        "       .set    noat            \n"
 138#ifdef CONFIG_32BIT
 139        "       addu    %0, %2          \n"
 140        "       sltu    $1, %0, %2      \n"
 141        "       addu    %0, $1          \n"
 142
 143        "       addu    %0, %3          \n"
 144        "       sltu    $1, %0, %3      \n"
 145        "       addu    %0, $1          \n"
 146
 147        "       addu    %0, %4          \n"
 148        "       sltu    $1, %0, %4      \n"
 149        "       addu    %0, $1          \n"
 150#endif
 151#ifdef CONFIG_64BIT
 152        "       daddu   %0, %2          \n"
 153        "       daddu   %0, %3          \n"
 154        "       daddu   %0, %4          \n"
 155        "       dsll32  $1, %0, 0       \n"
 156        "       daddu   %0, $1          \n"
 157        "       sltu    $1, %0, $1      \n"
 158        "       dsra32  %0, %0, 0       \n"
 159        "       addu    %0, $1          \n"
 160#endif
 161        "       .set    pop"
 162        : "=r" (tmp)
 163        : "0" ((__force unsigned long)daddr),
 164          "r" ((__force unsigned long)saddr),
 165#ifdef __MIPSEL__
 166          "r" ((proto + len) << 8),
 167#else
 168          "r" (proto + len),
 169#endif
 170          "r" ((__force unsigned long)sum));
 171
 172        return (__force __wsum)tmp;
 173}
 174#define csum_tcpudp_nofold csum_tcpudp_nofold
 175
 176/*
 177 * this routine is used for miscellaneous IP-like checksums, mainly
 178 * in icmp.c
 179 */
 180static inline __sum16 ip_compute_csum(const void *buff, int len)
 181{
 182        return csum_fold(csum_partial(buff, len, 0));
 183}
 184
 185#define _HAVE_ARCH_IPV6_CSUM
 186static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
 187                                          const struct in6_addr *daddr,
 188                                          __u32 len, __u8 proto,
 189                                          __wsum sum)
 190{
 191        __wsum tmp;
 192
 193        __asm__(
 194        "       .set    push            # csum_ipv6_magic\n"
 195        "       .set    noreorder       \n"
 196        "       .set    noat            \n"
 197        "       addu    %0, %5          # proto (long in network byte order)\n"
 198        "       sltu    $1, %0, %5      \n"
 199        "       addu    %0, $1          \n"
 200
 201        "       addu    %0, %6          # csum\n"
 202        "       sltu    $1, %0, %6      \n"
 203        "       lw      %1, 0(%2)       # four words source address\n"
 204        "       addu    %0, $1          \n"
 205        "       addu    %0, %1          \n"
 206        "       sltu    $1, %0, %1      \n"
 207
 208        "       lw      %1, 4(%2)       \n"
 209        "       addu    %0, $1          \n"
 210        "       addu    %0, %1          \n"
 211        "       sltu    $1, %0, %1      \n"
 212
 213        "       lw      %1, 8(%2)       \n"
 214        "       addu    %0, $1          \n"
 215        "       addu    %0, %1          \n"
 216        "       sltu    $1, %0, %1      \n"
 217
 218        "       lw      %1, 12(%2)      \n"
 219        "       addu    %0, $1          \n"
 220        "       addu    %0, %1          \n"
 221        "       sltu    $1, %0, %1      \n"
 222
 223        "       lw      %1, 0(%3)       \n"
 224        "       addu    %0, $1          \n"
 225        "       addu    %0, %1          \n"
 226        "       sltu    $1, %0, %1      \n"
 227
 228        "       lw      %1, 4(%3)       \n"
 229        "       addu    %0, $1          \n"
 230        "       addu    %0, %1          \n"
 231        "       sltu    $1, %0, %1      \n"
 232
 233        "       lw      %1, 8(%3)       \n"
 234        "       addu    %0, $1          \n"
 235        "       addu    %0, %1          \n"
 236        "       sltu    $1, %0, %1      \n"
 237
 238        "       lw      %1, 12(%3)      \n"
 239        "       addu    %0, $1          \n"
 240        "       addu    %0, %1          \n"
 241        "       sltu    $1, %0, %1      \n"
 242
 243        "       addu    %0, $1          # Add final carry\n"
 244        "       .set    pop"
 245        : "=&r" (sum), "=&r" (tmp)
 246        : "r" (saddr), "r" (daddr),
 247          "0" (htonl(len)), "r" (htonl(proto)), "r" (sum));
 248
 249        return csum_fold(sum);
 250}
 251
 252#include <asm-generic/checksum.h>
 253#endif /* CONFIG_GENERIC_CSUM */
 254
 255#endif /* _ASM_CHECKSUM_H */
 256