RTEMS CPU Kit with SuperCore  4.11.3
in_cksum_powerpc.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 the PowerPC 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 
21 #define LDTMP(n) tmp = *((u_int *)((u_char *)w + n))
22 
23 #define ADD(n) \
24  LDTMP(n); \
25  __asm__ volatile("addc %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp))
26 
27 #define ADDC(n) \
28  LDTMP(n); \
29  __asm__ volatile("adde %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp))
30 
31 #define MOP \
32  tmp = 0; \
33  __asm__ volatile("adde %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp))
34 
35 #define LOAD(n) junk = (u_char) *((volatile u_char *) w + n)
36 
37 
38 int
39 in_cksum(
40  struct mbuf *m,
41  int len
42 )
43 {
44  u_char junk;
45  register u_short *w;
46  register unsigned sum = 0;
47  register unsigned tmp;
48  register int mlen = 0;
49  int byte_swapped = 0;
50  union { char c[2]; u_short s; } su;
51 
52  for (;m && len; m = m->m_next) {
53  if (m->m_len == 0)
54  continue;
55  w = mtod(m, u_short *);
56  if (mlen == -1) {
57  /*
58  * The first byte of this mbuf is the continuation
59  * of a word spanning between this mbuf and the
60  * last mbuf.
61  */
62 
63  /* su.c[0] is already saved when scanning previous
64  * mbuf. sum was REDUCEd when we found mlen == -1
65  */
66  su.c[1] = *(u_char *)w;
67  sum += su.s;
68  w = (u_short *)((char *)w + 1);
69  mlen = m->m_len - 1;
70  len--;
71  } else
72  mlen = m->m_len;
73  if (len < mlen)
74  mlen = len;
75  len -= mlen;
76  /*
77  * Force to long boundary so we do longword aligned
78  * memory operations
79  */
80  if (3 & (int) w) {
81  REDUCE;
82  if ((1 & (int) w) && (mlen > 0)) {
83  sum <<= 8;
84  su.c[0] = *(char *)w;
85  w = (u_short *)((char *)w + 1);
86  mlen--;
87  byte_swapped = 1;
88  }
89  if ((2 & (int) w) && (mlen >= 2)) {
90  sum += *w++;
91  mlen -= 2;
92  }
93  }
94 
95  /*
96  * Do as much of the checksum as possible 32 bits at at time.
97  * In fact, this loop is unrolled to keep overhead from
98  * branches small.
99  */
100  while (mlen >= 32) {
101  /*
102  * Add with carry 16 words and fold in the last
103  * carry by adding a 0 with carry.
104  *
105  * The early ADD(16) and the LOAD(32) are intended
106  * to help get the data into the cache.
107  */
108  ADD(16);
109  ADDC(0);
110  ADDC(4);
111  ADDC(8);
112  ADDC(12);
113  LOAD(32);
114  ADDC(20);
115  ADDC(24);
116  ADDC(28);
117  MOP;
118  w += 16;
119  mlen -= 32;
120  }
121  if (mlen >= 16) {
122  ADD(0);
123  ADDC(4);
124  ADDC(8);
125  ADDC(12);
126  MOP;
127  w += 8;
128  mlen -= 16;
129  }
130  if (mlen >= 8) {
131  ADD(0);
132  ADDC(4);
133  MOP;
134  w += 4;
135  mlen -= 8;
136  }
137  if (mlen == 0 && byte_swapped == 0)
138  continue; /* worth 1% maybe ?? */
139  REDUCE;
140  while ((mlen -= 2) >= 0) {
141  sum += *w++;
142  }
143  if (byte_swapped) {
144  sum <<= 8;
145  byte_swapped = 0;
146  if (mlen == -1) {
147  su.c[1] = *(char *)w;
148  sum += su.s;
149  mlen = 0;
150  } else
151  mlen = -1;
152  } else if (mlen == -1)
153  /*
154  * This mbuf has odd number of bytes.
155  * There could be a word split betwen
156  * this mbuf and the next mbuf.
157  * Save the last byte (to prepend to next mbuf).
158  */
159  su.c[0] = *(char *)w;
160  }
161 
162  if (len)
163  puts("cksum: out of data");
164  if (mlen == -1) {
165  /* The last mbuf has odd # of bytes. Follow the
166  standard (the odd byte is shifted left by 8 bits) */
167  su.c[1] = 0;
168  sum += su.s;
169  }
170  REDUCE;
171  return (~sum & 0xffff);
172 }
Definition: mbuf.h:103