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