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