Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / arch / cris / arch-v32 / lib / checksum.S
1 /*
2  * A fast checksum routine using movem
3  * Copyright (c) 1998-2007 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         ;; Optimized for large packets
16         subq    10*4, $r11
17         blt     _word_loop
18         move.d  $r11, $acr
19
20         subq    9*4,$sp
21         clearf  c
22         movem   $r8,[$sp]
23
24         ;; do a movem checksum
25
26 _mloop: movem   [$r10+],$r9     ; read 10 longwords
27         ;; Loop count without touching the c flag.
28         addoq   -10*4, $acr, $acr
29         ;; perform dword checksumming on the 10 longwords
30
31         addc    $r0,$r12
32         addc    $r1,$r12
33         addc    $r2,$r12
34         addc    $r3,$r12
35         addc    $r4,$r12
36         addc    $r5,$r12
37         addc    $r6,$r12
38         addc    $r7,$r12
39         addc    $r8,$r12
40         addc    $r9,$r12
41
42         ;; test $acr without trashing carry.
43         move.d  $acr, $acr
44         bpl     _mloop
45         ;; r11 <= acr  is not really needed in the mloop, just using the dslot
46         ;; to prepare for what is needed after mloop.
47         move.d  $acr, $r11
48
49         ;; fold the last carry into r13
50         addc    0, $r12
51         movem   [$sp+],$r8      ; restore regs
52
53 _word_loop:
54         addq    10*4,$r11       ; compensate for last loop underflowing length
55
56         moveq   -1,$r9          ; put 0xffff in r9, faster than move.d 0xffff,r9
57         lsrq    16,$r9
58
59         move.d  $r12,$r13
60         lsrq    16,$r13         ; r13 = checksum >> 16
61         and.d   $r9,$r12        ; checksum = checksum & 0xffff
62
63 _no_fold:
64         subq    2,$r11
65         blt     _no_words
66         add.d   $r13,$r12       ; checksum += r13
67
68         ;; checksum the rest of the words
69 _wloop: subq    2,$r11
70         bge     _wloop
71         addu.w  [$r10+],$r12
72
73 _no_words:
74         addq    2,$r11
75         ;; see if we have one odd byte more
76         bne     _do_byte
77         nop
78         ret
79         move.d  $r12,$r10
80
81 _do_byte:
82         ;; copy and checksum the last byte
83         addu.b  [$r10],$r12
84         ret
85         move.d  $r12,$r10