The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/in_cksum.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1990 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      from tahoe:     in_cksum.c      1.2     86/01/05
   34  *      from:           @(#)in_cksum.c  1.3 (Berkeley) 1/19/91
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD: releng/5.2/sys/i386/i386/in_cksum.c 115683 2003-06-02 06:43:15Z obrien $");
   39 
   40 /*
   41  * MPsafe: alfred
   42  */
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/mbuf.h>
   46 
   47 #include <netinet/in.h>
   48 #include <netinet/in_systm.h>
   49 #include <netinet/ip.h>
   50 
   51 #include <machine/in_cksum.h>
   52 
   53 /*
   54  * Checksum routine for Internet Protocol family headers.
   55  *
   56  * This routine is very heavily used in the network
   57  * code and should be modified for each CPU to be as fast as possible.
   58  *
   59  * This implementation is 386 version.
   60  */
   61 
   62 #undef  ADDCARRY
   63 #define ADDCARRY(x)     if ((x) > 0xffff) (x) -= 0xffff
   64 #define REDUCE          {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
   65 
   66 /*
   67  * These asm statements require __volatile because they pass information
   68  * via the condition codes.  GCC does not currently provide a way to specify
   69  * the condition codes as an input or output operand.
   70  *
   71  * The LOAD macro below is effectively a prefetch into cache.  GCC will
   72  * load the value into a register but will not use it.  Since modern CPUs
   73  * reorder operations, this will generally take place in parallel with
   74  * other calculations.
   75  */
   76 #define ADD(n)  __asm __volatile \
   77                 ("addl %1, %0" : "+r" (sum) : \
   78                 "g" (((const u_int32_t *)w)[n / 4]))
   79 #define ADDC(n) __asm __volatile \
   80                 ("adcl %1, %0" : "+r" (sum) : \
   81                 "g" (((const u_int32_t *)w)[n / 4]))
   82 #define LOAD(n) __asm __volatile \
   83                 ("" : : "r" (((const u_int32_t *)w)[n / 4]))
   84 #define MOP     __asm __volatile \
   85                 ("adcl         $0, %0" : "+r" (sum))
   86 
   87 u_short
   88 in_cksum_skip(m, len, skip)
   89         struct mbuf *m;
   90         int len;
   91         int skip;
   92 {
   93         register u_short *w;
   94         register unsigned sum = 0;
   95         register int mlen = 0;
   96         int byte_swapped = 0;
   97         union { char    c[2]; u_short   s; } su;
   98 
   99         len -= skip;
  100         for (; skip && m; m = m->m_next) {
  101                 if (m->m_len > skip) {
  102                         mlen = m->m_len - skip;
  103                         w = (u_short *)(mtod(m, u_char *) + skip);
  104                         goto skip_start;
  105                 } else {
  106                         skip -= m->m_len;
  107                 }
  108         }
  109 
  110         for (;m && len; m = m->m_next) {
  111                 if (m->m_len == 0)
  112                         continue;
  113                 w = mtod(m, u_short *);
  114                 if (mlen == -1) {
  115                         /*
  116                          * The first byte of this mbuf is the continuation
  117                          * of a word spanning between this mbuf and the
  118                          * last mbuf.
  119                          */
  120 
  121                         /* su.c[0] is already saved when scanning previous
  122                          * mbuf.  sum was REDUCEd when we found mlen == -1
  123                          */
  124                         su.c[1] = *(u_char *)w;
  125                         sum += su.s;
  126                         w = (u_short *)((char *)w + 1);
  127                         mlen = m->m_len - 1;
  128                         len--;
  129                 } else
  130                         mlen = m->m_len;
  131 skip_start:
  132                 if (len < mlen)
  133                         mlen = len;
  134                 len -= mlen;
  135                 /*
  136                  * Force to long boundary so we do longword aligned
  137                  * memory operations
  138                  */
  139                 if (3 & (int) w) {
  140                         REDUCE;
  141                         if ((1 & (int) w) && (mlen > 0)) {
  142                                 sum <<= 8;
  143                                 su.c[0] = *(char *)w;
  144                                 w = (u_short *)((char *)w + 1);
  145                                 mlen--;
  146                                 byte_swapped = 1;
  147                         }
  148                         if ((2 & (int) w) && (mlen >= 2)) {
  149                                 sum += *w++;
  150                                 mlen -= 2;
  151                         }
  152                 }
  153                 /*
  154                  * Advance to a 486 cache line boundary.
  155                  */
  156                 if (4 & (int) w && mlen >= 4) {
  157                         ADD(0);
  158                         MOP;
  159                         w += 2;
  160                         mlen -= 4;
  161                 }
  162                 if (8 & (int) w && mlen >= 8) {
  163                         ADD(0);
  164                         ADDC(4);
  165                         MOP;
  166                         w += 4;
  167                         mlen -= 8;
  168                 }
  169                 /*
  170                  * Do as much of the checksum as possible 32 bits at at time.
  171                  * In fact, this loop is unrolled to make overhead from
  172                  * branches &c small.
  173                  */
  174                 mlen -= 1;
  175                 while ((mlen -= 32) >= 0) {
  176                         /*
  177                          * Add with carry 16 words and fold in the last
  178                          * carry by adding a 0 with carry.
  179                          *
  180                          * The early ADD(16) and the LOAD(32) are to load
  181                          * the next 2 cache lines in advance on 486's.  The
  182                          * 486 has a penalty of 2 clock cycles for loading
  183                          * a cache line, plus whatever time the external
  184                          * memory takes to load the first word(s) addressed.
  185                          * These penalties are unavoidable.  Subsequent
  186                          * accesses to a cache line being loaded (and to
  187                          * other external memory?) are delayed until the
  188                          * whole load finishes.  These penalties are mostly
  189                          * avoided by not accessing external memory for
  190                          * 8 cycles after the ADD(16) and 12 cycles after
  191                          * the LOAD(32).  The loop terminates when mlen
  192                          * is initially 33 (not 32) to guaranteed that
  193                          * the LOAD(32) is within bounds.
  194                          */
  195                         ADD(16);
  196                         ADDC(0);
  197                         ADDC(4);
  198                         ADDC(8);
  199                         ADDC(12);
  200                         LOAD(32);
  201                         ADDC(20);
  202                         ADDC(24);
  203                         ADDC(28);
  204                         MOP;
  205                         w += 16;
  206                 }
  207                 mlen += 32 + 1;
  208                 if (mlen >= 32) {
  209                         ADD(16);
  210                         ADDC(0);
  211                         ADDC(4);
  212                         ADDC(8);
  213                         ADDC(12);
  214                         ADDC(20);
  215                         ADDC(24);
  216                         ADDC(28);
  217                         MOP;
  218                         w += 16;
  219                         mlen -= 32;
  220                 }
  221                 if (mlen >= 16) {
  222                         ADD(0);
  223                         ADDC(4);
  224                         ADDC(8);
  225                         ADDC(12);
  226                         MOP;
  227                         w += 8;
  228                         mlen -= 16;
  229                 }
  230                 if (mlen >= 8) {
  231                         ADD(0);
  232                         ADDC(4);
  233                         MOP;
  234                         w += 4;
  235                         mlen -= 8;
  236                 }
  237                 if (mlen == 0 && byte_swapped == 0)
  238                         continue;       /* worth 1% maybe ?? */
  239                 REDUCE;
  240                 while ((mlen -= 2) >= 0) {
  241                         sum += *w++;
  242                 }
  243                 if (byte_swapped) {
  244                         sum <<= 8;
  245                         byte_swapped = 0;
  246                         if (mlen == -1) {
  247                                 su.c[1] = *(char *)w;
  248                                 sum += su.s;
  249                                 mlen = 0;
  250                         } else
  251                                 mlen = -1;
  252                 } else if (mlen == -1)
  253                         /*
  254                          * This mbuf has odd number of bytes.
  255                          * There could be a word split betwen
  256                          * this mbuf and the next mbuf.
  257                          * Save the last byte (to prepend to next mbuf).
  258                          */
  259                         su.c[0] = *(char *)w;
  260         }
  261 
  262         if (len)
  263                 printf("%s: out of data by %d\n", __func__, len);
  264         if (mlen == -1) {
  265                 /* The last mbuf has odd # of bytes. Follow the
  266                    standard (the odd byte is shifted left by 8 bits) */
  267                 su.c[1] = 0;
  268                 sum += su.s;
  269         }
  270         REDUCE;
  271         return (~sum & 0xffff);
  272 }

Cache object: d26b039fccaac7f4321bba0fbc0decac


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.