xref: /original-bsd/sys/vax/vax/in_cksum.c (revision f0fd5f8a)
1 /*	in_cksum.c	1.16	82/10/31	*/
2 
3 #include <sys/types.h>
4 #include "../h/mbuf.h"
5 #include "../netinet/in.h"
6 #include "../netinet/in_systm.h"
7 
8 /*
9  * Checksum routine for Internet Protocol family headers.
10  * This routine is very heavily used in the network
11  * code and should be modified for each CPU to be as fast as possible.
12  */
13 
14 in_cksum(m, len)
15 	register struct mbuf *m;
16 	register int len;
17 {
18 	register u_short *w;		/* on vax, known to be r9 */
19 	register int sum = 0;		/* on vax, known to be r8 */
20 	register int mlen = 0;
21 
22 	for (;;) {
23 		/*
24 		 * Each trip around loop adds in
25 		 * word from one mbuf segment.
26 		 */
27 		w = mtod(m, u_short *);
28 		if (mlen == -1) {
29 			/*
30 			 * There is a byte left from the last segment;
31 			 * add it into the checksum.  Don't have to worry
32 			 * about a carry-out here because we make sure
33 			 * that high part of (32 bit) sum is small below.
34 			 */
35 #ifdef sun
36 			sum += *(u_char *)w;
37 #endif
38 #ifdef vax
39 			sum += *(u_char *)w << 8;
40 #endif
41 			w = (u_short *)((char *)w + 1);
42 			mlen = m->m_len - 1;
43 			len--;
44 		} else
45 			mlen = m->m_len;
46 		m = m->m_next;
47 		if (len < mlen)
48 			mlen = len;
49 		len -= mlen;
50 #ifdef sun
51 		sum += ocsum(w, mlen>>1);
52 		w += mlen>>1;
53 #endif
54 #ifdef vax
55 		/*
56 		 * Force to long boundary so we do longword aligned
57 		 * memory operations.  It is too hard to do byte
58 		 * adjustment, do only word adjustment.
59 		 */
60 		if (((int)w&0x2) && mlen >= 2) {
61 			sum += *w++;
62 			mlen -= 2;
63 		}
64 		/*
65 		 * Do as much of the checksum as possible 32 bits at at time.
66 		 * In fact, this loop is unrolled to make overhead from
67 		 * branches &c small.
68 		 *
69 		 * We can do a 16 bit ones complement sum 32 bits at a time
70 		 * because the 32 bit register is acting as two 16 bit
71 		 * registers for adding, with carries from the low added
72 		 * into the high (by normal carry-chaining) and carries
73 		 * from the high carried into the low on the next word
74 		 * by use of the adwc instruction.  This lets us run
75 		 * this loop at almost memory speed.
76 		 *
77 		 * Here there is the danger of high order carry out, and
78 		 * we carefully use adwc.
79 		 */
80 		while ((mlen -= 32) >= 0) {
81 #undef ADD
82 			asm("clrl r0");		/* clears carry */
83 #define ADD		asm("adwc (r9)+,r8;");
84 			ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
85 			asm("adwc $0,r8");
86 		}
87 		mlen += 32;
88 		while ((mlen -= 8) >= 0) {
89 			asm("clrl r0");
90 			ADD; ADD;
91 			asm("adwc $0,r8");
92 		}
93 		mlen += 8;
94 		/*
95 		 * Now eliminate the possibility of carry-out's by
96 		 * folding back to a 16 bit number (adding high and
97 		 * low parts together.)  Then mop up trailing words
98 		 * and maybe an odd byte.
99 		 */
100 		{ asm("ashl $-16,r8,r0; addw2 r0,r8");
101 		  asm("adwc $0,r8; movzwl r8,r8"); }
102 		while ((mlen -= 2) >= 0) {
103 			asm("movzwl (r9)+,r0; addl2 r0,r8");
104 		}
105 		if (mlen == -1) {
106 			sum += *(u_char *)w;
107 		}
108 #endif vax
109 #ifdef sun
110 		if (mlen & 1) {
111 			sum += *(u_char *)w << 8;
112 			mlen = -1;
113 		}
114 #endif
115 		if (len == 0)
116 			break;
117 		/*
118 		 * Locate the next block with some data.
119 		 * If there is a word split across a boundary we
120 		 * will wrap to the top with mlen == -1 and
121 		 * then add it in shifted appropriately.
122 		 */
123 		for (;;) {
124 			if (m == 0) {
125 				printf("cksum: out of data\n");
126 				goto done;
127 			}
128 			if (m->m_len)
129 				break;
130 			m = m->m_next;
131 		}
132 	}
133 done:
134 	/*
135 	 * Add together high and low parts of sum
136 	 * and carry to get cksum.
137 	 * Have to be careful to not drop the last
138 	 * carry here.
139 	 */
140 #ifdef sun
141 	sum = (sum & 0xFFFF) + (sum >> 16);
142 	sum = (sum & 0xFFFF) + (sum >> 16);
143 	sum = (~sum) & 0xFFFF;
144 #endif
145 #ifdef vax
146 	{ asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8");
147 	  asm("mcoml r8,r8; movzwl r8,r8"); }
148 #endif
149 	return (sum);
150 }
151