akaros/kern/src/net/ptclbsum.c
<<
>>
Prefs
   1/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
   2 * Portions Copyright © 1997-1999 Vita Nuova Limited
   3 * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
   4 *                                (www.vitanuova.com)
   5 * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
   6 *
   7 * Modified for the Akaros operating system:
   8 * Copyright (c) 2013-2014 The Regents of the University of California
   9 * Copyright (c) 2013-2015 Google Inc.
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15 * copies of the Software, and to permit persons to whom the Software is
  16 * furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27 * SOFTWARE. */
  28
  29#include <slab.h>
  30#include <kmalloc.h>
  31#include <kref.h>
  32#include <string.h>
  33#include <stdio.h>
  34#include <assert.h>
  35#include <error.h>
  36#include <cpio.h>
  37#include <pmap.h>
  38#include <smp.h>
  39#include <net/ip.h>
  40#include <endian.h>
  41
  42static short endian = 1;
  43static uint8_t *aendian = (uint8_t *) & endian;
  44#define LITTLE  *aendian
  45
  46
  47#ifdef CONFIG_X86
  48
  49/* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
  50
  51/*-
  52 * Copyright (c) 1988, 1992, 1993
  53 *      The Regents of the University of California.  All rights reserved.
  54 * Copyright (c) 1996
  55 *      Matt Thomas <matt@3am-software.com>
  56 *
  57 * Redistribution and use in source and binary forms, with or without
  58 * modification, are permitted provided that the following conditions
  59 * are met:
  60 * 1. Redistributions of source code must retain the above copyright
  61 *    notice, this list of conditions and the following disclaimer.
  62 * 2. Redistributions in binary form must reproduce the above copyright
  63 *    notice, this list of conditions and the following disclaimer in the
  64 *    documentation and/or other materials provided with the distribution.
  65 * 3. All advertising materials mentioning features or use of this software
  66 *    must display the following acknowledgement:
  67 *      This product includes software developed by the University of
  68 *      California, Berkeley and its contributors.
  69 * 4. Neither the name of the University nor the names of its contributors
  70 *    may be used to endorse or promote products derived from this software
  71 *    without specific prior written permission.
  72 *
  73 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  74 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  76 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  77 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  78 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  79 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  80 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  83 * SUCH DAMAGE.
  84 *
  85 *      @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
  86 */
  87
  88/*
  89 * Checksum routine for Internet Protocol family headers
  90 *    (Portable Alpha version).
  91 *
  92 * This routine is very heavily used in the network
  93 * code and should be modified for each CPU to be as fast as possible.
  94 */
  95
  96#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
  97#define REDUCE32                                                          \
  98    {                                                                     \
  99        q_util.q = sum;                                                   \
 100        sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];      \
 101    }
 102#define REDUCE16                                                          \
 103    {                                                                     \
 104        q_util.q = sum;                                                   \
 105        l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
 106        sum = l_util.s[0] + l_util.s[1];                                  \
 107        ADDCARRY(sum);                                                    \
 108    }
 109
 110static const uint32_t in_masks[] = {
 111        /*0 bytes*/ /*1 byte*/  /*2 bytes*/ /*3 bytes*/
 112        0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF, /* offset 0 */
 113        0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00, /* offset 1 */
 114        0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000, /* offset 2 */
 115        0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, /* offset 3 */
 116};
 117
 118union l_util {
 119        uint16_t s[2];
 120        uint32_t l;
 121};
 122union q_util {
 123        uint16_t s[4];
 124        uint32_t l[2];
 125        uint64_t q;
 126};
 127
 128static uint64_t
 129in_cksumdata(const void *buf, int len)
 130{
 131        const uint32_t *lw = (const uint32_t *) buf;
 132        uint64_t sum = 0;
 133        uint64_t prefilled;
 134        int offset;
 135        union q_util q_util;
 136
 137        if ((3 & (long) lw) == 0 && len == 20) {
 138             sum = (uint64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
 139             REDUCE32;
 140             return sum;
 141        }
 142
 143        if ((offset = 3 & (long) lw) != 0) {
 144                const uint32_t *masks = in_masks + (offset << 2);
 145                lw = (uint32_t *) (((long) lw) - offset);
 146                sum = *lw++ & masks[len >= 3 ? 3 : len];
 147                len -= 4 - offset;
 148                if (len <= 0) {
 149                        REDUCE32;
 150                        return sum;
 151                }
 152        }
 153#if 0
 154        /*
 155         * Force to cache line boundary.
 156         */
 157        offset = 32 - (0x1f & (long) lw);
 158        if (offset < 32 && len > offset) {
 159                len -= offset;
 160                if (4 & offset) {
 161                        sum += (uint64_t) lw[0];
 162                        lw += 1;
 163                }
 164                if (8 & offset) {
 165                        sum += (uint64_t) lw[0] + lw[1];
 166                        lw += 2;
 167                }
 168                if (16 & offset) {
 169                        sum += (uint64_t) lw[0] + lw[1] + lw[2] + lw[3];
 170                        lw += 4;
 171                }
 172        }
 173#endif
 174        /*
 175         * access prefilling to start load of next cache line.
 176         * then add current cache line
 177         * save result of prefilling for loop iteration.
 178         */
 179        prefilled = lw[0];
 180        while ((len -= 32) >= 4) {
 181                uint64_t prefilling = lw[8];
 182                sum += prefilled + lw[1] + lw[2] + lw[3]
 183                        + lw[4] + lw[5] + lw[6] + lw[7];
 184                lw += 8;
 185                prefilled = prefilling;
 186        }
 187        if (len >= 0) {
 188                sum += prefilled + lw[1] + lw[2] + lw[3]
 189                        + lw[4] + lw[5] + lw[6] + lw[7];
 190                lw += 8;
 191        } else {
 192                len += 32;
 193        }
 194        while ((len -= 16) >= 0) {
 195                sum += (uint64_t) lw[0] + lw[1] + lw[2] + lw[3];
 196                lw += 4;
 197        }
 198        len += 16;
 199        while ((len -= 4) >= 0) {
 200                sum += (uint64_t) *lw++;
 201        }
 202        len += 4;
 203        if (len > 0)
 204                sum += (uint64_t) (in_masks[len] & *lw);
 205        REDUCE32;
 206        return sum;
 207}
 208uint16_t ptclbsum(uint8_t * addr, int len)
 209{
 210        uint64_t sum = in_cksumdata(addr, len);
 211        union q_util q_util;
 212        union l_util l_util;
 213        if ((uintptr_t)addr & 1)
 214                sum <<= 8;
 215        REDUCE16;
 216        return cpu_to_be16(sum);
 217}
 218#else
 219uint16_t ptclbsum(uint8_t * addr, int len)
 220{
 221        uint32_t losum, hisum, mdsum, x;
 222        uint32_t t1, t2;
 223
 224        losum = 0;
 225        hisum = 0;
 226        mdsum = 0;
 227
 228        x = 0;
 229        if ((uintptr_t) addr & 1) {
 230                if (len) {
 231                        hisum += addr[0];
 232                        len--;
 233                        addr++;
 234                }
 235                x = 1;
 236        }
 237        while (len >= 16) {
 238                t1 = *(uint16_t *) (addr + 0);
 239                t2 = *(uint16_t *) (addr + 2);
 240                mdsum += t1;
 241                t1 = *(uint16_t *) (addr + 4);
 242                mdsum += t2;
 243                t2 = *(uint16_t *) (addr + 6);
 244                mdsum += t1;
 245                t1 = *(uint16_t *) (addr + 8);
 246                mdsum += t2;
 247                t2 = *(uint16_t *) (addr + 10);
 248                mdsum += t1;
 249                t1 = *(uint16_t *) (addr + 12);
 250                mdsum += t2;
 251                t2 = *(uint16_t *) (addr + 14);
 252                mdsum += t1;
 253                mdsum += t2;
 254                len -= 16;
 255                addr += 16;
 256        }
 257        while (len >= 2) {
 258                mdsum += *(uint16_t *) addr;
 259                len -= 2;
 260                addr += 2;
 261        }
 262        if (x) {
 263                if (len)
 264                        losum += addr[0];
 265                if (LITTLE)
 266                        losum += mdsum;
 267                else
 268                        hisum += mdsum;
 269        } else {
 270                if (len)
 271                        hisum += addr[0];
 272                if (LITTLE)
 273                        hisum += mdsum;
 274                else
 275                        losum += mdsum;
 276        }
 277
 278        losum += hisum >> 8;
 279        losum += (hisum & 0xff) << 8;
 280        while ((hisum = losum >> 16))
 281                losum = hisum + (losum & 0xffff);
 282
 283        return losum & 0xffff;
 284}
 285#endif
 286