xref: /netbsd-src/sys/arch/arm/cortex/cpu_in_cksum_neon.c (revision 6df5b9a30995589b8535bc7a0d702d3e8e03ac4c)
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