source: rtems/c/src/libnetworking/netinet/in_cksum_i386.c @ 4de817d

4.104.114.84.95
Last change on this file since 4de817d was 4de817d, checked in by Joel Sherrill <joel.sherrill@…>, on 08/21/98 at 18:14:27

Added i386 specific version of in_cksum.c and restructured the main
file to switch out to CPU specific implementations.

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