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