Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[pandora-kernel.git] / arch / mips / lib / memset.S
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
7  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8  * Copyright (C) 2007 by Maciej W. Rozycki
9  * Copyright (C) 2011, 2012 MIPS Technologies, Inc.
10  */
11 #include <asm/asm.h>
12 #include <asm/asm-offsets.h>
13 #include <asm/regdef.h>
14
15 #if LONGSIZE == 4
16 #define LONG_S_L swl
17 #define LONG_S_R swr
18 #else
19 #define LONG_S_L sdl
20 #define LONG_S_R sdr
21 #endif
22
23 #ifdef CONFIG_CPU_MICROMIPS
24 #define STORSIZE (LONGSIZE * 2)
25 #define STORMASK (STORSIZE - 1)
26 #define FILL64RG t8
27 #define FILLPTRG t7
28 #undef  LONG_S
29 #define LONG_S LONG_SP
30 #else
31 #define STORSIZE LONGSIZE
32 #define STORMASK LONGMASK
33 #define FILL64RG a1
34 #define FILLPTRG t0
35 #endif
36
37 #define EX(insn,reg,addr,handler)                       \
38 9:      insn    reg, addr;                              \
39         .section __ex_table,"a";                        \
40         PTR     9b, handler;                            \
41         .previous
42
43         .macro  f_fill64 dst, offset, val, fixup
44         EX(LONG_S, \val, (\offset +  0 * STORSIZE)(\dst), \fixup)
45         EX(LONG_S, \val, (\offset +  1 * STORSIZE)(\dst), \fixup)
46         EX(LONG_S, \val, (\offset +  2 * STORSIZE)(\dst), \fixup)
47         EX(LONG_S, \val, (\offset +  3 * STORSIZE)(\dst), \fixup)
48 #if ((defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4)) || !defined(CONFIG_CPU_MICROMIPS))
49         EX(LONG_S, \val, (\offset +  4 * STORSIZE)(\dst), \fixup)
50         EX(LONG_S, \val, (\offset +  5 * STORSIZE)(\dst), \fixup)
51         EX(LONG_S, \val, (\offset +  6 * STORSIZE)(\dst), \fixup)
52         EX(LONG_S, \val, (\offset +  7 * STORSIZE)(\dst), \fixup)
53 #endif
54 #if (!defined(CONFIG_CPU_MICROMIPS) && (LONGSIZE == 4))
55         EX(LONG_S, \val, (\offset +  8 * STORSIZE)(\dst), \fixup)
56         EX(LONG_S, \val, (\offset +  9 * STORSIZE)(\dst), \fixup)
57         EX(LONG_S, \val, (\offset + 10 * STORSIZE)(\dst), \fixup)
58         EX(LONG_S, \val, (\offset + 11 * STORSIZE)(\dst), \fixup)
59         EX(LONG_S, \val, (\offset + 12 * STORSIZE)(\dst), \fixup)
60         EX(LONG_S, \val, (\offset + 13 * STORSIZE)(\dst), \fixup)
61         EX(LONG_S, \val, (\offset + 14 * STORSIZE)(\dst), \fixup)
62         EX(LONG_S, \val, (\offset + 15 * STORSIZE)(\dst), \fixup)
63 #endif
64         .endm
65
66 /*
67  * memset(void *s, int c, size_t n)
68  *
69  * a0: start of area to clear
70  * a1: char to fill with
71  * a2: size of area to clear
72  */
73         .set    noreorder
74         .align  5
75 LEAF(memset)
76         beqz            a1, 1f
77          move           v0, a0                  /* result */
78
79         andi            a1, 0xff                /* spread fillword */
80         LONG_SLL                t1, a1, 8
81         or              a1, t1
82         LONG_SLL                t1, a1, 16
83 #if LONGSIZE == 8
84         or              a1, t1
85         LONG_SLL                t1, a1, 32
86 #endif
87         or              a1, t1
88 1:
89
90 FEXPORT(__bzero)
91         sltiu           t0, a2, STORSIZE        /* very small region? */
92         bnez            t0, .Lsmall_memset
93          andi           t0, a0, STORMASK        /* aligned? */
94
95 #ifdef CONFIG_CPU_MICROMIPS
96         move            t8, a1                  /* used by 'swp' instruction */
97         move            t9, a1
98 #endif
99 #ifndef CONFIG_CPU_DADDI_WORKAROUNDS
100         beqz            t0, 1f
101          PTR_SUBU       t0, STORSIZE            /* alignment in bytes */
102 #else
103         .set            noat
104         li              AT, STORSIZE
105         beqz            t0, 1f
106          PTR_SUBU       t0, AT                  /* alignment in bytes */
107         .set            at
108 #endif
109
110         R10KCBARRIER(0(ra))
111 #ifdef __MIPSEB__
112         EX(LONG_S_L, a1, (a0), .Lfirst_fixup)   /* make word/dword aligned */
113 #endif
114 #ifdef __MIPSEL__
115         EX(LONG_S_R, a1, (a0), .Lfirst_fixup)   /* make word/dword aligned */
116 #endif
117         PTR_SUBU        a0, t0                  /* long align ptr */
118         PTR_ADDU        a2, t0                  /* correct size */
119
120 1:      ori             t1, a2, 0x3f            /* # of full blocks */
121         xori            t1, 0x3f
122         beqz            t1, .Lmemset_partial    /* no block to fill */
123          andi           t0, a2, 0x40-STORSIZE
124
125         PTR_ADDU        t1, a0                  /* end address */
126         .set            reorder
127 1:      PTR_ADDIU       a0, 64
128         R10KCBARRIER(0(ra))
129         f_fill64 a0, -64, FILL64RG, .Lfwd_fixup
130         bne             t1, a0, 1b
131         .set            noreorder
132
133 .Lmemset_partial:
134         R10KCBARRIER(0(ra))
135         PTR_LA          t1, 2f                  /* where to start */
136 #ifdef CONFIG_CPU_MICROMIPS
137         LONG_SRL        t7, t0, 1
138 #endif
139 #if LONGSIZE == 4
140         PTR_SUBU        t1, FILLPTRG
141 #else
142         .set            noat
143         LONG_SRL        AT, FILLPTRG, 1
144         PTR_SUBU        t1, AT
145         .set            at
146 #endif
147         jr              t1
148          PTR_ADDU       a0, t0                  /* dest ptr */
149
150         .set            push
151         .set            noreorder
152         .set            nomacro
153         f_fill64 a0, -64, FILL64RG, .Lpartial_fixup     /* ... but first do longs ... */
154 2:      .set            pop
155         andi            a2, STORMASK            /* At most one long to go */
156
157         beqz            a2, 1f
158          PTR_ADDU       a0, a2                  /* What's left */
159         R10KCBARRIER(0(ra))
160 #ifdef __MIPSEB__
161         EX(LONG_S_R, a1, -1(a0), .Llast_fixup)
162 #endif
163 #ifdef __MIPSEL__
164         EX(LONG_S_L, a1, -1(a0), .Llast_fixup)
165 #endif
166 1:      jr              ra
167          move           a2, zero
168
169 .Lsmall_memset:
170         beqz            a2, 2f
171          PTR_ADDU       t1, a0, a2
172
173 1:      PTR_ADDIU       a0, 1                   /* fill bytewise */
174         R10KCBARRIER(0(ra))
175         bne             t1, a0, 1b
176          sb             a1, -1(a0)
177
178 2:      jr              ra                      /* done */
179          move           a2, zero
180         END(memset)
181
182 .Lfirst_fixup:
183         jr      ra
184          nop
185
186 .Lfwd_fixup:
187         PTR_L           t0, TI_TASK($28)
188         andi            a2, 0x3f
189         LONG_L          t0, THREAD_BUADDR(t0)
190         LONG_ADDU       a2, t1
191         jr              ra
192          LONG_SUBU      a2, t0
193
194 .Lpartial_fixup:
195         PTR_L           t0, TI_TASK($28)
196         andi            a2, STORMASK
197         LONG_L          t0, THREAD_BUADDR(t0)
198         LONG_ADDU       a2, t1
199         jr              ra
200          LONG_SUBU      a2, t0
201
202 .Llast_fixup:
203         jr              ra
204          andi           v1, a2, STORMASK