source: rtems/cpukit/libnetworking/netinet/in_cksum_i386.c @ 4bf1801

4.104.114.84.95
Last change on this file since 4bf1801 was eb0d7ae, checked in by Joel Sherrill <joel.sherrill@…>, on 01/04/99 at 16:35:31

Patch from D. V. Henkel-Wallace <gumby@…> to use puts and have prototype.

  • Property mode set to 100644
File size: 4.4 KB
Line 
1/*
2 * Checksum routine for Internet Protocol family headers.
3 *
4 * This routine is very heavily used in the network
5 * code and should be modified for each CPU to be as fast as possible.
6 *
7 * This implementation is 386 version.
8 *
9 *  $Id$
10 */
11
12#include <stdio.h>                /* for puts */
13
14#undef  ADDCARRY
15#define ADDCARRY(x)     if ((x) > 0xffff) (x) -= 0xffff
16#define REDUCE          {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
17
18/*
19 * Thanks to gcc we don't have to guess
20 * which registers contain sum & w.
21 */
22#define ADD(n)  asm("addl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w))
23#define ADDC(n) asm("adcl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w))
24#define LOAD(n) asm volatile("movb " #n "(%1), %0" : "=r" (junk) : "r" (w))
25#define MOP     asm("adcl         $0, %0" : "=r" (sum) : "0" (sum))
26
27int
28in_cksum(m, len)
29        register struct mbuf *m;
30        register int len;
31{
32        register u_short *w;
33        register unsigned sum = 0;
34        register int mlen = 0;
35        int byte_swapped = 0;
36        union { char    c[2]; u_short   s; } su;
37
38        for (;m && len; m = m->m_next) {
39                if (m->m_len == 0)
40                        continue;
41                w = mtod(m, u_short *);
42                if (mlen == -1) {
43                        /*
44                         * The first byte of this mbuf is the continuation
45                         * of a word spanning between this mbuf and the
46                         * last mbuf.
47                         */
48
49                        /* su.c[0] is already saved when scanning previous
50                         * mbuf.  sum was REDUCEd when we found mlen == -1
51                         */
52                        su.c[1] = *(u_char *)w;
53                        sum += su.s;
54                        w = (u_short *)((char *)w + 1);
55                        mlen = m->m_len - 1;
56                        len--;
57                } else
58                        mlen = m->m_len;
59                if (len < mlen)
60                        mlen = len;
61                len -= mlen;
62                /*
63                 * Force to long boundary so we do longword aligned
64                 * memory operations
65                 */
66                if (3 & (int) w) {
67                        REDUCE;
68                        if ((1 & (int) w) && (mlen > 0)) {
69                                sum <<= 8;
70                                su.c[0] = *(char *)w;
71                                w = (u_short *)((char *)w + 1);
72                                mlen--;
73                                byte_swapped = 1;
74                        }
75                        if ((2 & (int) w) && (mlen >= 2)) {
76                                sum += *w++;
77                                mlen -= 2;
78                        }
79                }
80                /*
81                 * Advance to a 486 cache line boundary.
82                 */
83                if (4 & (int) w && mlen >= 4) {
84                        ADD(0);
85                        MOP;
86                        w += 2;
87                        mlen -= 4;
88                }
89                if (8 & (int) w && mlen >= 8) {
90                        ADD(0);
91                        ADDC(4);
92                        MOP;
93                        w += 4;
94                        mlen -= 8;
95                }
96                /*
97                 * Do as much of the checksum as possible 32 bits at at time.
98                 * In fact, this loop is unrolled to make overhead from
99                 * branches &c small.
100                 */
101                mlen -= 1;
102                while ((mlen -= 32) >= 0) {
103                        u_char junk;
104                        /*
105                         * Add with carry 16 words and fold in the last
106                         * carry by adding a 0 with carry.
107                         *
108                         * The early ADD(16) and the LOAD(32) are to load
109                         * the next 2 cache lines in advance on 486's.  The
110                         * 486 has a penalty of 2 clock cycles for loading
111                         * a cache line, plus whatever time the external
112                         * memory takes to load the first word(s) addressed.
113                         * These penalties are unavoidable.  Subsequent
114                         * accesses to a cache line being loaded (and to
115                         * other external memory?) are delayed until the
116                         * whole load finishes.  These penalties are mostly
117                         * avoided by not accessing external memory for
118                         * 8 cycles after the ADD(16) and 12 cycles after
119                         * the LOAD(32).  The loop terminates when mlen
120                         * is initially 33 (not 32) to guaranteed that
121                         * the LOAD(32) is within bounds.
122                         */
123                        ADD(16);
124                        ADDC(0);
125                        ADDC(4);
126                        ADDC(8);
127                        ADDC(12);
128                        LOAD(32);
129                        ADDC(20);
130                        ADDC(24);
131                        ADDC(28);
132                        MOP;
133                        w += 16;
134                }
135                mlen += 32 + 1;
136                if (mlen >= 32) {
137                        ADD(16);
138                        ADDC(0);
139                        ADDC(4);
140                        ADDC(8);
141                        ADDC(12);
142                        ADDC(20);
143                        ADDC(24);
144                        ADDC(28);
145                        MOP;
146                        w += 16;
147                        mlen -= 32;
148                }
149                if (mlen >= 16) {
150                        ADD(0);
151                        ADDC(4);
152                        ADDC(8);
153                        ADDC(12);
154                        MOP;
155                        w += 8;
156                        mlen -= 16;
157                }
158                if (mlen >= 8) {
159                        ADD(0);
160                        ADDC(4);
161                        MOP;
162                        w += 4;
163                        mlen -= 8;
164                }
165                if (mlen == 0 && byte_swapped == 0)
166                        continue;       /* worth 1% maybe ?? */
167                REDUCE;
168                while ((mlen -= 2) >= 0) {
169                        sum += *w++;
170                }
171                if (byte_swapped) {
172                        sum <<= 8;
173                        byte_swapped = 0;
174                        if (mlen == -1) {
175                                su.c[1] = *(char *)w;
176                                sum += su.s;
177                                mlen = 0;
178                        } else
179                                mlen = -1;
180                } else if (mlen == -1)
181                        /*
182                         * This mbuf has odd number of bytes.
183                         * There could be a word split betwen
184                         * this mbuf and the next mbuf.
185                         * Save the last byte (to prepend to next mbuf).
186                         */
187                        su.c[0] = *(char *)w;
188        }
189
190        if (len)
191                puts("cksum: out of data");
192        if (mlen == -1) {
193                /* The last mbuf has odd # of bytes. Follow the
194                   standard (the odd byte is shifted left by 8 bits) */
195                su.c[1] = 0;
196                sum += su.s;
197        }
198        REDUCE;
199        return (~sum & 0xffff);
200}
Note: See TracBrowser for help on using the repository browser.