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