source: rtems/cpukit/libnetworking/netinet/in_cksum_i386.h @ 4273e70

4.104.114.95
Last change on this file since 4273e70 was 4273e70, checked in by Joel Sherrill <joel.sherrill@…>, on 02/06/08 at 16:59:31

2008-02-06 Joel Sherrill <joel.sherrill@…>

PR 1277/networking

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