RTEMS CPU Kit with SuperCore  4.11.3
in_cksum_nios2.h
Go to the documentation of this file.
1 
2 /*
3  * Altera Nios2 CRC checksum computation
4  *
5  * Author: Jeffrey O. Hill
6  *
7  * Copyright 2012. Los Alamos National Security, LLC.
8  * This material was produced under U.S. Government contract
9  * DE-AC52-06NA25396 for Los Alamos National Laboratory (LANL),
10  * which is operated by Los Alamos National Security, LLC for
11  * the U.S. Department of Energy. The U.S. Government has rights
12  * to use, reproduce, and distribute this software. NEITHER THE
13  * GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC MAKES ANY
14  * WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR
15  * THE USE OF THIS SOFTWARE.
16  *
17  * COPYRIGHT (c) 1989-2012.
18  * On-Line Applications Research Corporation (OAR).
19  *
20  * Copyright (c) 1997 Mark Brinicome
21  * Copyright (c) 1997 Causality Limited
22  *
23  * Copyright (c) 1995 Zubin Dittia.
24  * Copyright (c) 1995 Matthew R. Green.
25  * Copyright (c) 1994 Charles M. Hannum.
26  * Copyright (c) 1992, 1993
27  * The Regents of the University of California. All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  * 1. Redistributions of source code must retain the above copyright
33  * notice, this list of conditions and the following disclaimer.
34  * 2. Redistributions in binary form must reproduce the above copyright
35  * notice, this list of conditions and the following disclaimer in the
36  * documentation and/or other materials provided with the distribution.
37  * 3. All advertising materials mentioning features or use of this software
38  * must display the following acknowledgement:
39  * This product includes software developed by the University of
40  * California, Berkeley and its contributors.
41  * 4. Neither the name of the University nor the names of its contributors
42  * may be used to endorse or promote products derived from this software
43  * without specific prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  * Based on the arm / sparc version, but using instead
58  * mostly inline functions in place of naaasty macros.
59  *
60  * It would be a great idea to somehow detect at runtime
61  * that the Nios2 has a user defined instruction that
62  * computes the CRC and invoke it here (we could call a
63  * function in the BSP).
64  */
65 
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/mbuf.h>
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/ip.h>
72 #include <netinet/ip_var.h>
73 #include <machine/in_cksum.h>
74 
75 /*
76  * Checksum routine for Internet Protocol family headers.
77  *
78  * This routine is very heavily used in the network
79  * code and should be modified for each CPU to be as fast as possible.
80  */
81 static inline uint32_t _NIOS2_Add_ones_complement_64
82 ( uint32_t sum, const uint32_t * const pWd )
83 {
84  sum = _NIOS2_Add_ones_complement ( sum, pWd[0] );
85  sum = _NIOS2_Add_ones_complement ( sum, pWd[1] );
86  sum = _NIOS2_Add_ones_complement ( sum, pWd[2] );
87  sum = _NIOS2_Add_ones_complement ( sum, pWd[3] );
88  sum = _NIOS2_Add_ones_complement ( sum, pWd[4] );
89  sum = _NIOS2_Add_ones_complement ( sum, pWd[5] );
90  sum = _NIOS2_Add_ones_complement ( sum, pWd[6] );
91  sum = _NIOS2_Add_ones_complement ( sum, pWd[7] );
92  sum = _NIOS2_Add_ones_complement ( sum, pWd[8] );
93  sum = _NIOS2_Add_ones_complement ( sum, pWd[9] );
94  sum = _NIOS2_Add_ones_complement ( sum, pWd[10] );
95  sum = _NIOS2_Add_ones_complement ( sum, pWd[11] );
96  sum = _NIOS2_Add_ones_complement ( sum, pWd[12] );
97  sum = _NIOS2_Add_ones_complement ( sum, pWd[13] );
98  sum = _NIOS2_Add_ones_complement ( sum, pWd[14] );
99  return _NIOS2_Add_ones_complement ( sum, pWd[15] );
100 }
101 
102 static inline uint32_t _NIOS2_Add_ones_complement_32
103 ( uint32_t sum, const uint32_t * const pWd )
104 {
105  sum = _NIOS2_Add_ones_complement ( sum, pWd[0] );
106  sum = _NIOS2_Add_ones_complement ( sum, pWd[1] );
107  sum = _NIOS2_Add_ones_complement ( sum, pWd[2] );
108  sum = _NIOS2_Add_ones_complement ( sum, pWd[3] );
109  sum = _NIOS2_Add_ones_complement ( sum, pWd[4] );
110  sum = _NIOS2_Add_ones_complement ( sum, pWd[5] );
111  sum = _NIOS2_Add_ones_complement ( sum, pWd[6] );
112  return _NIOS2_Add_ones_complement ( sum, pWd[7] );
113 }
114 
115 static inline uint32_t _NIOS2_Add_ones_complement_16
116 ( uint32_t sum, const uint32_t * const pWd )
117 {
118  sum = _NIOS2_Add_ones_complement ( sum, pWd[0] );
119  sum = _NIOS2_Add_ones_complement ( sum, pWd[1] );
120  sum = _NIOS2_Add_ones_complement ( sum, pWd[2] );
121  return _NIOS2_Add_ones_complement ( sum, pWd[3] );
122 }
123 
124 static inline uint32_t _NIOS2_Add_ones_complement_8
125 ( uint32_t sum, const uint32_t * const pWd )
126 {
127  sum = _NIOS2_Add_ones_complement ( sum, pWd[0] );
128  return _NIOS2_Add_ones_complement ( sum, pWd[1] );
129 }
130 
131 static inline uint32_t _NIOS2_Add_ones_complement_4
132 ( uint32_t sum, const uint32_t * const pWd )
133 {
134  return _NIOS2_Add_ones_complement ( sum, pWd[0] );
135 }
136 
137 static inline uint32_t _NIOS2_Reduce_checksum ( uint32_t a )
138 {
139  uint32_t tmp;
140  __asm__ __volatile__ (
141  " srli %1, %0, 16 \n" /* tmp = a >> 16 */
142  " andi %0, %0, 0xffff \n" /* a = a & 0xffff */
143  " add %0, %0, %1 \n" /* a = a + tmp */
144  : "+&r"(a), "=&r"(tmp)
145  );
146  return a;
147 }
148 
149 #define combineTokens( A, B ) A ## B
150 
151 #define ADD_AND_ADVANCE( N ) \
152 if ( mlen >= N ) { \
153  sum = combineTokens ( _NIOS2_Add_ones_complement_, N ) \
154  ( sum, ( uint32_t * ) w ); \
155  mlen -= N; \
156  w += N; \
157 }
158 
159 static int
160 in_cksum_internal(struct mbuf *m, int off, int len, u_int sum)
161 {
162  const uint8_t * w;
163  int mlen = 0;
164  int byte_swapped = 0;
165 
166  for (; m && len; m = m->m_next)
167  {
168  if (m->m_len == 0)
169  continue;
170  w = mtod(m, u_char *) + off;
171  mlen = m->m_len - off;
172  off = 0;
173  if (len < mlen)
174  mlen = len;
175  len -= mlen;
176 
177  /*
178  * Ensure that we're aligned on a word boundary here so
179  * that we can do 32 bit operations below.
180  */
181  if ((3 & (uint32_t)w) != 0)
182  {
183  sum = _NIOS2_Reduce_checksum ( sum );
184  if ((1 & (uint32_t)w) != 0 && mlen >= 1)
185  {
186  sum <<= 8u;
187  sum += *w << 8u;
188  byte_swapped ^= 1;
189  w += 1;
190  mlen -= 1;
191  }
192  if ((2 & (uint32_t)w) != 0 && mlen >= 2)
193  {
194  sum += *(uint16_t *)w;
195  w += 2;
196  mlen -= 2;
197  }
198  }
199 
200  /*
201  * instead of using a loop, process in unrolled chunks
202  */
203  while ( mlen >= 64 )
204  {
205  sum = _NIOS2_Add_ones_complement_64
206  ( sum, ( uint32_t * ) w );
207  mlen -= 64;
208  w += 64;
209  }
210  ADD_AND_ADVANCE ( 32 );
211  ADD_AND_ADVANCE ( 16 );
212  ADD_AND_ADVANCE ( 8 );
213  ADD_AND_ADVANCE ( 4 );
214 
215  if ( mlen > 0 )
216  {
217  sum = _NIOS2_Reduce_checksum ( sum );
218  if ( mlen >= 2 )
219  {
220  sum += *(uint16_t *)w;
221  w += 2;
222  mlen -= 2;
223  }
224  if ( mlen == 1 )
225  {
226  sum <<= 8u;
227  sum += *w << 8u;
228  byte_swapped ^= 1;
229  }
230  }
231  }
232  if ( byte_swapped )
233  {
234  sum = _NIOS2_Reduce_checksum ( sum );
235  sum <<= 8u;
236  }
237  sum = _NIOS2_Add_ones_complement_word_halves ( sum );
238  sum ^= 0xffff;
239  return sum;
240 }
241 
242 int
243 in_cksum (
244  struct mbuf *m,
245  int len )
246 {
247  return in_cksum_internal ( m, 0, len, 0 );
248 }
249 
250 int
251 in4_cksum (
252  struct mbuf *m,
253  u_int8_t nxt,
254  int off,
255  int len )
256 {
257  u_int sum = 0;
258 
259  if ( nxt != 0 )
260  {
261  struct ipovly ipov;
262  /* pseudo header */
263  if (off < sizeof(struct ipovly))
264  panic("in4_cksum: offset too short");
265  if (m->m_len < sizeof(struct ip))
266  panic("in4_cksum: bad mbuf chain");
267 
268  bzero(&ipov, sizeof(ipov));
269  ipov.ih_len = htons(len);
270  ipov.ih_pr = nxt;
271  ipov.ih_src = mtod(m, struct ip *)->ip_src;
272  ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
273  u_char * w = (u_char *)&ipov;
274 
275  if ( sizeof(ipov) != 20 )
276  panic( "in4_cksum: sizeof(ipov) != 20" );
277  sum = _NIOS2_Add_ones_complement_16 ( sum, (uint32_t *) w );
278  w += 16;
279  sum = _NIOS2_Add_ones_complement_4 ( sum, (uint32_t *) w );
280  }
281  /* skip unnecessary part */
282  while (m && off > 0)
283  {
284  if (m->m_len > off)
285  break;
286  off -= m->m_len;
287  m = m->m_next;
288  }
289  return (in_cksum_internal(m, off, len, sum));
290 }
291 
292 
register struct Per_CPU_Control *_SPARC_Per_CPU_current __asm__("g6")
The pointer to the current per-CPU control is available via register g6.
Definition: ip.h:61
Definition: ip_var.h:43
Definition: mbuf.h:103