Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
[linux-2.6] / 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  */
9 #include <asm/asm.h>
10 #include <asm/asm-offsets.h>
11 #include <asm/regdef.h>
12
13 #if LONGSIZE == 4
14 #define LONG_S_L swl
15 #define LONG_S_R swr
16 #else
17 #define LONG_S_L sdl
18 #define LONG_S_R sdr
19 #endif
20
21 #define EX(insn,reg,addr,handler)                       \
22 9:      insn    reg, addr;                              \
23         .section __ex_table,"a";                        \
24         PTR     9b, handler;                            \
25         .previous
26
27         .macro  f_fill64 dst, offset, val, fixup
28         EX(LONG_S, \val, (\offset +  0 * LONGSIZE)(\dst), \fixup)
29         EX(LONG_S, \val, (\offset +  1 * LONGSIZE)(\dst), \fixup)
30         EX(LONG_S, \val, (\offset +  2 * LONGSIZE)(\dst), \fixup)
31         EX(LONG_S, \val, (\offset +  3 * LONGSIZE)(\dst), \fixup)
32         EX(LONG_S, \val, (\offset +  4 * LONGSIZE)(\dst), \fixup)
33         EX(LONG_S, \val, (\offset +  5 * LONGSIZE)(\dst), \fixup)
34         EX(LONG_S, \val, (\offset +  6 * LONGSIZE)(\dst), \fixup)
35         EX(LONG_S, \val, (\offset +  7 * LONGSIZE)(\dst), \fixup)
36 #if LONGSIZE == 4
37         EX(LONG_S, \val, (\offset +  8 * LONGSIZE)(\dst), \fixup)
38         EX(LONG_S, \val, (\offset +  9 * LONGSIZE)(\dst), \fixup)
39         EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup)
40         EX(LONG_S, \val, (\offset + 11 * LONGSIZE)(\dst), \fixup)
41         EX(LONG_S, \val, (\offset + 12 * LONGSIZE)(\dst), \fixup)
42         EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup)
43         EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup)
44         EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup)
45 #endif
46         .endm
47
48 /*
49  * memset(void *s, int c, size_t n)
50  *
51  * a0: start of area to clear
52  * a1: char to fill with
53  * a2: size of area to clear
54  */
55         .set    noreorder
56         .align  5
57 LEAF(memset)
58         beqz            a1, 1f
59          move           v0, a0                  /* result */
60
61         andi            a1, 0xff                /* spread fillword */
62         LONG_SLL                t1, a1, 8
63         or              a1, t1
64         LONG_SLL                t1, a1, 16
65 #if LONGSIZE == 8
66         or              a1, t1
67         LONG_SLL                t1, a1, 32
68 #endif
69         or              a1, t1
70 1:
71
72 FEXPORT(__bzero)
73         sltiu           t0, a2, LONGSIZE        /* very small region? */
74         bnez            t0, small_memset
75          andi           t0, a0, LONGMASK        /* aligned? */
76
77         beqz            t0, 1f
78          PTR_SUBU       t0, LONGSIZE            /* alignment in bytes */
79
80 #ifdef __MIPSEB__
81         EX(LONG_S_L, a1, (a0), first_fixup)     /* make word/dword aligned */
82 #endif
83 #ifdef __MIPSEL__
84         EX(LONG_S_R, a1, (a0), first_fixup)     /* make word/dword aligned */
85 #endif
86         PTR_SUBU        a0, t0                  /* long align ptr */
87         PTR_ADDU        a2, t0                  /* correct size */
88
89 1:      ori             t1, a2, 0x3f            /* # of full blocks */
90         xori            t1, 0x3f
91         beqz            t1, memset_partial      /* no block to fill */
92          andi           t0, a2, 0x40-LONGSIZE
93
94         PTR_ADDU        t1, a0                  /* end address */
95         .set            reorder
96 1:      PTR_ADDIU       a0, 64
97         f_fill64 a0, -64, a1, fwd_fixup
98         bne             t1, a0, 1b
99         .set            noreorder
100
101 memset_partial:
102         PTR_LA          t1, 2f                  /* where to start */
103 #if LONGSIZE == 4
104         PTR_SUBU        t1, t0
105 #else
106         .set            noat
107         LONG_SRL                AT, t0, 1
108         PTR_SUBU        t1, AT
109         .set            noat
110 #endif
111         jr              t1
112          PTR_ADDU       a0, t0                  /* dest ptr */
113
114         .set            push
115         .set            noreorder
116         .set            nomacro
117         f_fill64 a0, -64, a1, partial_fixup     /* ... but first do longs ... */
118 2:      .set            pop
119         andi            a2, LONGMASK            /* At most one long to go */
120
121         beqz            a2, 1f
122          PTR_ADDU       a0, a2                  /* What's left */
123 #ifdef __MIPSEB__
124         EX(LONG_S_R, a1, -1(a0), last_fixup)
125 #endif
126 #ifdef __MIPSEL__
127         EX(LONG_S_L, a1, -1(a0), last_fixup)
128 #endif
129 1:      jr              ra
130          move           a2, zero
131
132 small_memset:
133         beqz            a2, 2f
134          PTR_ADDU       t1, a0, a2
135
136 1:      PTR_ADDIU       a0, 1                   /* fill bytewise */
137         bne             t1, a0, 1b
138          sb             a1, -1(a0)
139
140 2:      jr              ra                      /* done */
141          move           a2, zero
142         END(memset)
143
144 first_fixup:
145         jr      ra
146          nop
147
148 fwd_fixup:
149         PTR_L           t0, TI_TASK($28)
150         LONG_L          t0, THREAD_BUADDR(t0)
151         andi            a2, 0x3f
152         LONG_ADDU       a2, t1
153         jr              ra
154          LONG_SUBU      a2, t0
155
156 partial_fixup:
157         PTR_L           t0, TI_TASK($28)
158         LONG_L          t0, THREAD_BUADDR(t0)
159         andi            a2, LONGMASK
160         LONG_ADDU       a2, t1
161         jr              ra
162          LONG_SUBU      a2, t0
163
164 last_fixup:
165         jr              ra
166          andi           v1, a2, LONGMASK