Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[cascardo/linux.git] / arch / arm / lib / memzero.S
1 /*
2  *  linux/arch/arm/lib/memzero.S
3  *
4  *  Copyright (C) 1995-2000 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/linkage.h>
11 #include <asm/assembler.h>
12 #include <asm/unwind.h>
13 #include <asm/export.h>
14
15         .text
16         .align  5
17         .word   0
18 /*
19  * Align the pointer in r0.  r3 contains the number of bytes that we are
20  * mis-aligned by, and r1 is the number of bytes.  If r1 < 4, then we
21  * don't bother; we use byte stores instead.
22  */
23 UNWIND( .fnstart                        )
24 1:      subs    r1, r1, #4              @ 1 do we have enough
25         blt     5f                      @ 1 bytes to align with?
26         cmp     r3, #2                  @ 1
27         strltb  r2, [r0], #1            @ 1
28         strleb  r2, [r0], #1            @ 1
29         strb    r2, [r0], #1            @ 1
30         add     r1, r1, r3              @ 1 (r1 = r1 - (4 - r3))
31 /*
32  * The pointer is now aligned and the length is adjusted.  Try doing the
33  * memzero again.
34  */
35
36 ENTRY(__memzero)
37         mov     r2, #0                  @ 1
38         ands    r3, r0, #3              @ 1 unaligned?
39         bne     1b                      @ 1
40 /*
41  * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary.
42  */
43         cmp     r1, #16                 @ 1 we can skip this chunk if we
44         blt     4f                      @ 1 have < 16 bytes
45
46 #if ! CALGN(1)+0
47
48 /*
49  * We need an extra register for this loop - save the return address and
50  * use the LR
51  */
52         str     lr, [sp, #-4]!          @ 1
53 UNWIND( .fnend                          )
54 UNWIND( .fnstart                        )
55 UNWIND( .save   {lr}                    )
56         mov     ip, r2                  @ 1
57         mov     lr, r2                  @ 1
58
59 3:      subs    r1, r1, #64             @ 1 write 32 bytes out per loop
60         stmgeia r0!, {r2, r3, ip, lr}   @ 4
61         stmgeia r0!, {r2, r3, ip, lr}   @ 4
62         stmgeia r0!, {r2, r3, ip, lr}   @ 4
63         stmgeia r0!, {r2, r3, ip, lr}   @ 4
64         bgt     3b                      @ 1
65         ldmeqfd sp!, {pc}               @ 1/2 quick exit
66 /*
67  * No need to correct the count; we're only testing bits from now on
68  */
69         tst     r1, #32                 @ 1
70         stmneia r0!, {r2, r3, ip, lr}   @ 4
71         stmneia r0!, {r2, r3, ip, lr}   @ 4
72         tst     r1, #16                 @ 1 16 bytes or more?
73         stmneia r0!, {r2, r3, ip, lr}   @ 4
74         ldr     lr, [sp], #4            @ 1
75 UNWIND( .fnend                          )
76
77 #else
78
79 /*
80  * This version aligns the destination pointer in order to write
81  * whole cache lines at once.
82  */
83
84         stmfd   sp!, {r4-r7, lr}
85 UNWIND( .fnend                 )
86 UNWIND( .fnstart               )
87 UNWIND( .save   {r4-r7, lr}    )
88         mov     r4, r2
89         mov     r5, r2
90         mov     r6, r2
91         mov     r7, r2
92         mov     ip, r2
93         mov     lr, r2
94
95         cmp     r1, #96
96         andgts  ip, r0, #31
97         ble     3f
98
99         rsb     ip, ip, #32
100         sub     r1, r1, ip
101         movs    ip, ip, lsl #(32 - 4)
102         stmcsia r0!, {r4, r5, r6, r7}
103         stmmiia r0!, {r4, r5}
104         movs    ip, ip, lsl #2
105         strcs   r2, [r0], #4
106
107 3:      subs    r1, r1, #64
108         stmgeia r0!, {r2-r7, ip, lr}
109         stmgeia r0!, {r2-r7, ip, lr}
110         bgt     3b
111         ldmeqfd sp!, {r4-r7, pc}
112
113         tst     r1, #32
114         stmneia r0!, {r2-r7, ip, lr}
115         tst     r1, #16
116         stmneia r0!, {r4-r7}
117         ldmfd   sp!, {r4-r7, lr}
118 UNWIND( .fnend                 )
119
120 #endif
121
122 UNWIND( .fnstart                        )
123 4:      tst     r1, #8                  @ 1 8 bytes or more?
124         stmneia r0!, {r2, r3}           @ 2
125         tst     r1, #4                  @ 1 4 bytes or more?
126         strne   r2, [r0], #4            @ 1
127 /*
128  * When we get here, we've got less than 4 bytes to zero.  We
129  * may have an unaligned pointer as well.
130  */
131 5:      tst     r1, #2                  @ 1 2 bytes or more?
132         strneb  r2, [r0], #1            @ 1
133         strneb  r2, [r0], #1            @ 1
134         tst     r1, #1                  @ 1 a byte left over
135         strneb  r2, [r0], #1            @ 1
136         ret     lr                      @ 1
137 UNWIND( .fnend                          )
138 ENDPROC(__memzero)
139 EXPORT_SYMBOL(__memzero)