Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / arch / cris / arch-v32 / lib / checksumcopy.S
1 /*
2  * A fast checksum+copy routine using movem
3  * Copyright (c) 1998, 2001, 2003 Axis Communications AB
4  *
5  * Authors:     Bjorn Wesen
6  *
7  * csum_partial_copy_nocheck(const char *src, char *dst,
8  *                           int len, unsigned int sum)
9  */
10
11         .globl  csum_partial_copy_nocheck
12 csum_partial_copy_nocheck:
13
14         ;; r10 - src
15         ;; r11 - dst
16         ;; r12 - length
17         ;; r13 - checksum
18
19         ;; check for breakeven length between movem and normal word looping versions
20         ;; we also do _NOT_ want to compute a checksum over more than the
21         ;; actual length when length < 40
22
23         cmpu.w  80,$r12
24         blo     _word_loop
25         nop
26
27         ;; need to save the registers we use below in the movem loop
28         ;; this overhead is why we have a check above for breakeven length
29         ;; only r0 - r8 have to be saved, the other ones are clobber-able
30         ;; according to the ABI
31
32         subq    9*4,$sp
33         subq    10*4,$r12       ; update length for the first loop
34         movem   $r8,[$sp]
35
36         ;; do a movem copy and checksum
37
38 1:      ;; A failing userspace access (the read) will have this as PC.
39 _mloop: movem   [$r10+],$r9     ; read 10 longwords
40         movem   $r9,[$r11+]     ; write 10 longwords
41
42         ;; perform dword checksumming on the 10 longwords
43
44         add.d   $r0,$r13
45         addc    $r1,$r13
46         addc    $r2,$r13
47         addc    $r3,$r13
48         addc    $r4,$r13
49         addc    $r5,$r13
50         addc    $r6,$r13
51         addc    $r7,$r13
52         addc    $r8,$r13
53         addc    $r9,$r13
54
55         ;; fold the carry into the checksum, to avoid having to loop the carry
56         ;; back into the top
57
58         addc    0,$r13
59         addc    0,$r13          ; do it again, since we might have generated a carry
60
61         subq    10*4,$r12
62         bge     _mloop
63         nop
64
65         addq    10*4,$r12       ; compensate for last loop underflowing length
66
67         movem   [$sp+],$r8      ; restore regs
68
69 _word_loop:
70         ;; only fold if there is anything to fold.
71
72         cmpq    0,$r13
73         beq     _no_fold
74
75         ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
76         ;; r9 can be used as temporary.
77
78         move.d  $r13,$r9
79         lsrq    16,$r9          ; r0 = checksum >> 16
80         and.d   0xffff,$r13     ; checksum = checksum & 0xffff
81         add.d   $r9,$r13        ; checksum += r0
82         move.d  $r13,$r9        ; do the same again, maybe we got a carry last add
83         lsrq    16,$r9
84         and.d   0xffff,$r13
85         add.d   $r9,$r13
86
87 _no_fold:
88         cmpq    2,$r12
89         blt     _no_words
90         nop
91
92         ;; copy and checksum the rest of the words
93
94         subq    2,$r12
95
96 2:      ;; A failing userspace access for the read below will have this as PC.
97 _wloop: move.w  [$r10+],$r9
98         addu.w  $r9,$r13
99         subq    2,$r12
100         bge     _wloop
101         move.w  $r9,[$r11+]
102
103         addq    2,$r12
104
105 _no_words:
106         ;; see if we have one odd byte more
107         cmpq    1,$r12
108         beq     _do_byte
109         nop
110         ret
111         move.d  $r13,$r10
112
113 _do_byte:
114         ;; copy and checksum the last byte
115 3:      ;; A failing userspace access for the read below will have this as PC.
116         move.b  [$r10],$r9
117         addu.b  $r9,$r13
118         move.b  $r9,[$r11]
119         ret
120         move.d  $r13,$r10