OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [alpha/] [lib/] [csum_partial_copy.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * csum_partial_copy - do IP checksumming and copy
3
 *
4
 * (C) Copyright 1996 Linus Torvalds
5
 *
6
 * Don't look at this too closely - you'll go mad. The things
7
 * we do for performance..
8
 */
9
 
10
#define ldq_u(x,y) \
11
__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(unsigned long *)(y)))
12
 
13
#define stq_u(x,y) \
14
__asm__ __volatile__("stq_u %1,%0":"=m" (*(unsigned long *)(y)):"r" (x))
15
 
16
#define extql(x,y,z) \
17
__asm__ __volatile__("extql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
18
 
19
#define extqh(x,y,z) \
20
__asm__ __volatile__("extqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
21
 
22
#define mskql(x,y,z) \
23
__asm__ __volatile__("mskql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
24
 
25
#define mskqh(x,y,z) \
26
__asm__ __volatile__("mskqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
27
 
28
#define insql(x,y,z) \
29
__asm__ __volatile__("insql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
30
 
31
#define insqh(x,y,z) \
32
__asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
33
 
34
/*
35
 * Ok. This isn't fun, but this is the EASY case.
36
 */
37
static inline unsigned long csum_partial_copy_aligned(
38
        unsigned long *src, unsigned long *dst,
39
        long len, unsigned long checksum)
40
{
41
        unsigned long carry = 0;
42
 
43
        while (len >= 0) {
44
                unsigned long word = *src;
45
                checksum += carry;
46
                src++;
47
                checksum += word;
48
                len -= 8;
49
                carry = checksum < word;
50
                *dst = word;
51
                dst++;
52
        }
53
        len += 8;
54
        checksum += carry;
55
        if (len) {
56
                unsigned long word, tmp;
57
                word = *src;
58
                tmp = *dst;
59
                mskql(word, len, word);
60
                checksum += word;
61
                mskqh(tmp, len, tmp);
62
                carry = checksum < word;
63
                *dst = word | tmp;
64
                checksum += carry;
65
        }
66
        return checksum;
67
}
68
 
69
/*
70
 * This is even less fun, but this is still reasonably
71
 * easy.
72
 */
73
static inline unsigned long csum_partial_copy_dest_aligned(
74
        unsigned long *src, unsigned long *dst,
75
        unsigned long soff,
76
        long len, unsigned long checksum)
77
{
78
        unsigned long first;
79
        unsigned long word, carry;
80
        unsigned long lastsrc = 7+len+(unsigned long)src;
81
 
82
        ldq_u(first,src);
83
        carry = 0;
84
        while (len >= 0) {
85
                unsigned long second;
86
 
87
                ldq_u(second, src+1);
88
                extql(first, soff, word);
89
                len -= 8;
90
                src++;
91
                extqh(second, soff, first);
92
                checksum += carry;
93
                word |= first;
94
                first = second;
95
                checksum += word;
96
                *dst = word;
97
                dst++;
98
                carry = checksum < word;
99
        }
100
        len += 8;
101
        checksum += carry;
102
        if (len) {
103
                unsigned long tmp;
104
                unsigned long second;
105
                ldq_u(second, lastsrc);
106
                tmp = *dst;
107
                extql(first, soff, word);
108
                extqh(second, soff, first);
109
                word |= first;
110
                mskql(word, len, word);
111
                checksum += word;
112
                mskqh(tmp, len, tmp);
113
                carry = checksum < word;
114
                *dst = word | tmp;
115
                checksum += carry;
116
        }
117
        return checksum;
118
}
119
 
120
/*
121
 * This is slightly less fun than the above..
122
 */
123
static inline unsigned long csum_partial_copy_src_aligned(
124
        unsigned long *src, unsigned long *dst,
125
        unsigned long doff,
126
        long len, unsigned long checksum,
127
        unsigned long partial_dest)
128
{
129
        unsigned long carry = 0;
130
        unsigned long word;
131
 
132
        mskql(partial_dest, doff, partial_dest);
133
        while (len >= 0) {
134
                unsigned long second_dest;
135
                word = *src;
136
                len -= 8;
137
                insql(word, doff, second_dest);
138
                checksum += carry;
139
                stq_u(partial_dest | second_dest, dst);
140
                src++;
141
                checksum += word;
142
                insqh(word, doff, partial_dest);
143
                carry = checksum < word;
144
                dst++;
145
        }
146
        len += doff;
147
        checksum += carry;
148
        if (len >= 0) {
149
                unsigned long second_dest;
150
                word = *src;
151
                mskql(word, len-doff, word);
152
                checksum += word;
153
                insql(word, doff, second_dest);
154
                stq_u(partial_dest | second_dest, dst);
155
                carry = checksum < word;
156
                if (len) {
157
                        ldq_u(second_dest, dst+1);
158
                        insqh(word, doff, partial_dest);
159
                        mskqh(second_dest, len, second_dest);
160
                        stq_u(partial_dest | second_dest, dst+1);
161
                }
162
                checksum += carry;
163
        } else if (len & 7) {
164
                unsigned long second_dest;
165
                word = *src;
166
                ldq_u(second_dest, dst);
167
                mskql(word, len-doff, word);
168
                checksum += word;
169
                mskqh(second_dest, len, second_dest);
170
                carry = checksum < word;
171
                insql(word, doff, word);
172
                stq_u(partial_dest | word | second_dest, dst);
173
                checksum += carry;
174
        }
175
        return checksum;
176
}
177
 
178
/*
179
 * This is so totally un-fun that it's frightening. Don't
180
 * look at this too closely, you'll go blind.
181
 */
182
static inline unsigned long csum_partial_copy_unaligned(
183
        unsigned long * src, unsigned long * dst,
184
        unsigned long soff, unsigned long doff,
185
        long len, unsigned long checksum,
186
        unsigned long partial_dest)
187
{
188
        unsigned long carry = 0;
189
        unsigned long first;
190
        unsigned long lastsrc;
191
 
192
        ldq_u(first, src);
193
        lastsrc = 7+len+(unsigned long)src;
194
        mskql(partial_dest, doff, partial_dest);
195
        while (len >= 0) {
196
                unsigned long second, word;
197
                unsigned long second_dest;
198
 
199
                ldq_u(second, src+1);
200
                extql(first, soff, word);
201
                checksum += carry;
202
                len -= 8;
203
                extqh(second, soff, first);
204
                src++;
205
                word |= first;
206
                first = second;
207
                insql(word, doff, second_dest);
208
                checksum += word;
209
                stq_u(partial_dest | second_dest, dst);
210
                carry = checksum < word;
211
                insqh(word, doff, partial_dest);
212
                dst++;
213
        }
214
        len += doff;
215
        checksum += carry;
216
        if (len >= 0) {
217
                unsigned long second, word;
218
                unsigned long second_dest;
219
 
220
                ldq_u(second, lastsrc);
221
                extql(first, soff, word);
222
                extqh(second, soff, first);
223
                word |= first;
224
                first = second;
225
                mskql(word, len-doff, word);
226
                checksum += word;
227
                insql(word, doff, second_dest);
228
                carry = checksum < word;
229
                stq_u(partial_dest | second_dest, dst);
230
                if (len) {
231
                        ldq_u(second_dest, dst+1);
232
                        insqh(word, doff, partial_dest);
233
                        mskqh(second_dest, len, second_dest);
234
                        stq_u(partial_dest | second_dest, dst+1);
235
                }
236
                checksum += carry;
237
        } else if (len & 7) {
238
                unsigned long second, word;
239
                unsigned long second_dest;
240
 
241
                ldq_u(second, lastsrc);
242
                extql(first, soff, word);
243
                extqh(second, soff, first);
244
                word |= first;
245
                ldq_u(second_dest, dst);
246
                mskql(word, len-doff, word);
247
                checksum += word;
248
                mskqh(second_dest, len, second_dest);
249
                carry = checksum < word;
250
                insql(word, doff, word);
251
                stq_u(partial_dest | word | second_dest, dst);
252
                checksum += carry;
253
        }
254
        return checksum;
255
}
256
 
257
unsigned int csum_partial_copy(char *src, char *dst, int len, int sum)
258
{
259
        unsigned long checksum = (unsigned) sum;
260
        unsigned long soff = 7 & (unsigned long) src;
261
        unsigned long doff = 7 & (unsigned long) dst;
262
 
263
        if (len) {
264
                if (!doff) {
265
                        if (!soff)
266
                                checksum = csum_partial_copy_aligned(
267
                                        (unsigned long *) src,
268
                                        (unsigned long *) dst,
269
                                        len-8, checksum);
270
                        else
271
                                checksum = csum_partial_copy_dest_aligned(
272
                                        (unsigned long *) src,
273
                                        (unsigned long *) dst,
274
                                        soff, len-8, checksum);
275
                } else {
276
                        unsigned long partial_dest;
277
                        ldq_u(partial_dest, dst);
278
                        if (!soff)
279
                                checksum = csum_partial_copy_src_aligned(
280
                                        (unsigned long *) src,
281
                                        (unsigned long *) dst,
282
                                        doff, len-8, checksum,
283
                                        partial_dest);
284
                        else
285
                                checksum = csum_partial_copy_unaligned(
286
                                        (unsigned long *) src,
287
                                        (unsigned long *) dst,
288
                                        soff, doff, len-8, checksum,
289
                                        partial_dest);
290
                }
291
                /* 64 -> 33 bits */
292
                checksum = (checksum & 0xffffffff) + (checksum >> 32);
293
                /* 33 -> < 32 bits */
294
                checksum = (checksum & 0xffff) + (checksum >> 16);
295
                /* 32 -> 16 bits */
296
                checksum = (checksum & 0xffff) + (checksum >> 16);
297
                checksum = (checksum & 0xffff) + (checksum >> 16);
298
        }
299
        return checksum;
300
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.