1 /*-
2 * Copyright (c) 2012 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Matt Thomas of 3am Software Foundry.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31
32 __KERNEL_RCSID(0, "$NetBSD: cpu_in_cksum_neon.c,v 1.1 2012/12/17 00:44:03 matt Exp $");
33
34 #include <sys/param.h>
35 #include <sys/cpu.h>
36 #include <sys/mbuf.h>
37
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40
41 uint32_t cpu_in_cksum_neon(const void *, size_t);
42 uint32_t cpu_in_cksum_neon_v4hdr(const void *);
43
44 int
cpu_in_cksum(struct mbuf * m,int len,int off,uint32_t initial_sum)45 cpu_in_cksum(struct mbuf *m, int len, int off, uint32_t initial_sum)
46 {
47 uint32_t csum = initial_sum;
48 int odd = 0;
49
50 /*
51 * Taken control of the NEON PCU.
52 */
53 vfp_hijack();
54
55 /*
56 * Fast path for the normal ip_header
57 */
58 if (off == 0
59 && csum == 0
60 && len == sizeof(struct ip)
61 && ((uintptr_t)m->m_data & 3) == 0
62 && m->m_len >= len) {
63 csum = cpu_in_cksum_neon_v4hdr(m->m_data);
64
65 /*
66 * We are now down with NEON.
67 */
68 vfp_surrender();
69
70 if (csum == 0x10000) /* note 0x10000 - 0xffff == 1 */
71 return 1;
72 return csum == 0 ? 0xffff : csum; /* never return 0. */
73 }
74
75 /*
76 * Skip the initial mbufs
77 */
78 while (m->m_len >= off) {
79 m = m->m_next;
80 off -= m->m_len;
81 KASSERT(m != NULL);
82 }
83
84 for (; len > 0; m = m->m_next, off = 0) {
85 KASSERT(m != NULL);
86 int dlen = MIN(m->m_len - off, len);
87 const void *dptr = m->m_data + off;
88 /*
89 * This routine will add based on the memory layout so
90 * if the previous len was odd or the this buffer starts
91 * on an odd address, shift the csum by 8 so its properly
92 * aligned. It will be taken care of when we do the final
93 * checksum fold.
94 */
95 uint32_t tmpsum = cpu_in_cksum_neon(dptr, dlen);
96 if (odd ^ ((uint32_t)dptr & 1))
97 tmpsum <<= 8;
98 /*
99 * Accumulate checksum, folding will be done later
100 */
101 csum += tmpsum;
102 odd ^= dlen & 1;
103 len -= dlen;
104 }
105
106 /*
107 * We are now down with NEON.
108 */
109 vfp_surrender();
110
111 /*
112 * Time to fold the checksum
113 */
114 csum = (csum >> 16) + (csum & 0xffff);
115 /*
116 * Now it could be 0x1xxxx so fold again
117 */
118 csum = (csum >> 16) + (csum & 0xffff);
119
120 KASSERT(csum <= 0x10000);
121 if (csum == 0x10000) /* note 0x10000 - 0xffff == 1 */
122 return 1;
123 return csum == 0 ? 0xffff : csum; /* never return 0. */
124 }
125