BSD 4_3_Reno development
[unix-history] / .ref-BSD-4_3_Tahoe / usr / src / sys / vax / in_cksum.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
5f7901a4 3 * All rights reserved.
da7c5cc6 4 *
5f7901a4 5 * Redistribution and use in source and binary forms are permitted
616d42db
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5f7901a4 16 *
ca67e7b4 17 * @(#)in_cksum.c 7.3 (Berkeley) 6/29/88
da7c5cc6 18 */
51041fae 19
1884f3f6
JB
20#include "types.h"
21#include "mbuf.h"
51041fae
BJ
22
23/*
e1cdb8f4
SL
24 * Checksum routine for Internet Protocol family headers (VAX Version).
25 *
2b4b57cd 26 * This routine is very heavily used in the network
9a480eec 27 * code and should be modified for each CPU to be as fast as possible.
51041fae 28 */
51041fae 29
8a13b737 30in_cksum(m, len)
51041fae
BJ
31 register struct mbuf *m;
32 register int len;
33{
9a480eec
BJ
34 register u_short *w; /* on vax, known to be r9 */
35 register int sum = 0; /* on vax, known to be r8 */
51041fae 36 register int mlen = 0;
51041fae
BJ
37
38 for (;;) {
2b4b57cd
BJ
39 /*
40 * Each trip around loop adds in
41 * word from one mbuf segment.
42 */
43 w = mtod(m, u_short *);
51041fae 44 if (mlen == -1) {
2b4b57cd
BJ
45 /*
46 * There is a byte left from the last segment;
47 * add it into the checksum. Don't have to worry
48 * about a carry-out here because we make sure
49 * that high part of (32 bit) sum is small below.
50 */
51041fae 51 sum += *(u_char *)w << 8;
e6dd2097 52 w = (u_short *)((char *)w + 1);
51041fae
BJ
53 mlen = m->m_len - 1;
54 len--;
55 } else
56 mlen = m->m_len;
57 m = m->m_next;
58 if (len < mlen)
59 mlen = len;
60 len -= mlen;
2b4b57cd
BJ
61 /*
62 * Force to long boundary so we do longword aligned
63 * memory operations. It is too hard to do byte
64 * adjustment, do only word adjustment.
65 */
66 if (((int)w&0x2) && mlen >= 2) {
67 sum += *w++;
68 mlen -= 2;
69 }
70 /*
71 * Do as much of the checksum as possible 32 bits at at time.
72 * In fact, this loop is unrolled to make overhead from
73 * branches &c small.
74 *
75 * We can do a 16 bit ones complement sum 32 bits at a time
76 * because the 32 bit register is acting as two 16 bit
77 * registers for adding, with carries from the low added
78 * into the high (by normal carry-chaining) and carries
79 * from the high carried into the low on the next word
80 * by use of the adwc instruction. This lets us run
81 * this loop at almost memory speed.
82 *
83 * Here there is the danger of high order carry out, and
84 * we carefully use adwc.
85 */
51041fae 86 while ((mlen -= 32) >= 0) {
4d0a6cbd 87#undef ADD
1fd3f510
MK
88#ifdef unneeded /* The loop construct clears carry for us... */
89 asm("bicpsr $1"); /* clears carry */
90#endif
4d0a6cbd 91#define ADD asm("adwc (r9)+,r8;");
51041fae 92 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
4d0a6cbd 93 asm("adwc $0,r8");
51041fae
BJ
94 }
95 mlen += 32;
96 while ((mlen -= 8) >= 0) {
1fd3f510
MK
97#ifdef unneeded /* The loop construct clears carry for us... */
98 asm("bicpsr $1"); /* clears carry */
99#endif
4d0a6cbd
BJ
100 ADD; ADD;
101 asm("adwc $0,r8");
51041fae
BJ
102 }
103 mlen += 8;
2b4b57cd
BJ
104 /*
105 * Now eliminate the possibility of carry-out's by
106 * folding back to a 16 bit number (adding high and
107 * low parts together.) Then mop up trailing words
108 * and maybe an odd byte.
109 */
110 { asm("ashl $-16,r8,r0; addw2 r0,r8");
111 asm("adwc $0,r8; movzwl r8,r8"); }
51041fae 112 while ((mlen -= 2) >= 0) {
2b4b57cd 113 asm("movzwl (r9)+,r0; addl2 r0,r8");
51041fae 114 }
9a480eec 115 if (mlen == -1) {
51041fae 116 sum += *(u_char *)w;
9a480eec 117 }
51041fae
BJ
118 if (len == 0)
119 break;
2b4b57cd
BJ
120 /*
121 * Locate the next block with some data.
122 * If there is a word split across a boundary we
123 * will wrap to the top with mlen == -1 and
124 * then add it in shifted appropriately.
125 */
51041fae 126 for (;;) {
f248b7ed 127 if (m == 0) {
e6dd2097 128 printf("cksum: out of data\n");
f248b7ed
BJ
129 goto done;
130 }
51041fae
BJ
131 if (m->m_len)
132 break;
133 m = m->m_next;
134 }
135 }
f248b7ed 136done:
2b4b57cd
BJ
137 /*
138 * Add together high and low parts of sum
139 * and carry to get cksum.
140 * Have to be careful to not drop the last
141 * carry here.
142 */
e6dd2097
BJ
143 { asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8");
144 asm("mcoml r8,r8; movzwl r8,r8"); }
145 return (sum);
51041fae 146}