Merge branches 'work.misc' and 'work.dcache' of git://git.kernel.org/pub/scm/linux...
[sfrench/cifs-2.6.git] / arch / parisc / lib / lusercopy.S
1 /*
2  *    User Space Access Routines
3  *
4  *    Copyright (C) 2000-2002 Hewlett-Packard (John Marvin)
5  *    Copyright (C) 2000 Richard Hirst <rhirst with parisc-linux.org>
6  *    Copyright (C) 2001 Matthieu Delahaye <delahaym at esiee.fr>
7  *    Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org>
8  *    Copyright (C) 2017 Helge Deller <deller@gmx.de>
9  *    Copyright (C) 2017 John David Anglin <dave.anglin@bell.net>
10  *
11  *
12  *    This program is free software; you can redistribute it and/or modify
13  *    it under the terms of the GNU General Public License as published by
14  *    the Free Software Foundation; either version 2, or (at your option)
15  *    any later version.
16  *
17  *    This program is distributed in the hope that it will be useful,
18  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *    GNU General Public License for more details.
21  *
22  *    You should have received a copy of the GNU General Public License
23  *    along with this program; if not, write to the Free Software
24  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 /*
28  * These routines still have plenty of room for optimization
29  * (word & doubleword load/store, dual issue, store hints, etc.).
30  */
31
32 /*
33  * The following routines assume that space register 3 (sr3) contains
34  * the space id associated with the current users address space.
35  */
36
37
38         .text
39         
40 #include <asm/assembly.h>
41 #include <asm/errno.h>
42 #include <linux/linkage.h>
43
44         /*
45          * get_sr gets the appropriate space value into
46          * sr1 for kernel/user space access, depending
47          * on the flag stored in the task structure.
48          */
49
50         .macro  get_sr
51         mfctl       %cr30,%r1
52         ldw         TI_SEGMENT(%r1),%r22
53         mfsp        %sr3,%r1
54         or,<>       %r22,%r0,%r0
55         copy        %r0,%r1
56         mtsp        %r1,%sr1
57         .endm
58
59         /*
60          * unsigned long lclear_user(void *to, unsigned long n)
61          *
62          * Returns 0 for success.
63          * otherwise, returns number of bytes not transferred.
64          */
65
66 ENTRY_CFI(lclear_user)
67         comib,=,n   0,%r25,$lclu_done
68         get_sr
69 $lclu_loop:
70         addib,<>    -1,%r25,$lclu_loop
71 1:      stbs,ma     %r0,1(%sr1,%r26)
72
73 $lclu_done:
74         bv          %r0(%r2)
75         copy        %r25,%r28
76
77 2:      b           $lclu_done
78         ldo         1(%r25),%r25
79
80         ASM_EXCEPTIONTABLE_ENTRY(1b,2b)
81 ENDPROC_CFI(lclear_user)
82
83
84         /*
85          * long lstrnlen_user(char *s, long n)
86          *
87          * Returns 0 if exception before zero byte or reaching N,
88          *         N+1 if N would be exceeded,
89          *         else strlen + 1 (i.e. includes zero byte).
90          */
91
92 ENTRY_CFI(lstrnlen_user)
93         comib,=     0,%r25,$lslen_nzero
94         copy        %r26,%r24
95         get_sr
96 1:      ldbs,ma     1(%sr1,%r26),%r1
97 $lslen_loop:
98         comib,=,n   0,%r1,$lslen_done
99         addib,<>    -1,%r25,$lslen_loop
100 2:      ldbs,ma     1(%sr1,%r26),%r1
101 $lslen_done:
102         bv          %r0(%r2)
103         sub         %r26,%r24,%r28
104
105 $lslen_nzero:
106         b           $lslen_done
107         ldo         1(%r26),%r26 /* special case for N == 0 */
108
109 3:      b           $lslen_done
110         copy        %r24,%r26    /* reset r26 so 0 is returned on fault */
111
112         ASM_EXCEPTIONTABLE_ENTRY(1b,3b)
113         ASM_EXCEPTIONTABLE_ENTRY(2b,3b)
114
115 ENDPROC_CFI(lstrnlen_user)
116
117
118 /*
119  * unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
120  *
121  * Inputs:
122  * - sr1 already contains space of source region
123  * - sr2 already contains space of destination region
124  *
125  * Returns:
126  * - number of bytes that could not be copied.
127  *   On success, this will be zero.
128  *
129  * This code is based on a C-implementation of a copy routine written by
130  * Randolph Chung, which in turn was derived from the glibc.
131  *
132  * Several strategies are tried to try to get the best performance for various
133  * conditions. In the optimal case, we copy by loops that copy 32- or 16-bytes
134  * at a time using general registers.  Unaligned copies are handled either by
135  * aligning the destination and then using shift-and-write method, or in a few
136  * cases by falling back to a byte-at-a-time copy.
137  *
138  * Testing with various alignments and buffer sizes shows that this code is
139  * often >10x faster than a simple byte-at-a-time copy, even for strangely
140  * aligned operands. It is interesting to note that the glibc version of memcpy
141  * (written in C) is actually quite fast already. This routine is able to beat
142  * it by 30-40% for aligned copies because of the loop unrolling, but in some
143  * cases the glibc version is still slightly faster. This lends more
144  * credibility that gcc can generate very good code as long as we are careful.
145  *
146  * Possible optimizations:
147  * - add cache prefetching
148  * - try not to use the post-increment address modifiers; they may create
149  *   additional interlocks. Assumption is that those were only efficient on old
150  *   machines (pre PA8000 processors)
151  */
152
153         dst = arg0
154         src = arg1
155         len = arg2
156         end = arg3
157         t1  = r19
158         t2  = r20
159         t3  = r21
160         t4  = r22
161         srcspc = sr1
162         dstspc = sr2
163
164         t0 = r1
165         a1 = t1
166         a2 = t2
167         a3 = t3
168         a0 = t4
169
170         save_src = ret0
171         save_dst = ret1
172         save_len = r31
173
174 ENTRY_CFI(pa_memcpy)
175         /* Last destination address */
176         add     dst,len,end
177
178         /* short copy with less than 16 bytes? */
179         cmpib,COND(>>=),n 15,len,.Lbyte_loop
180
181         /* same alignment? */
182         xor     src,dst,t0
183         extru   t0,31,2,t1
184         cmpib,<>,n  0,t1,.Lunaligned_copy
185
186 #ifdef CONFIG_64BIT
187         /* only do 64-bit copies if we can get aligned. */
188         extru   t0,31,3,t1
189         cmpib,<>,n  0,t1,.Lalign_loop32
190
191         /* loop until we are 64-bit aligned */
192 .Lalign_loop64:
193         extru   dst,31,3,t1
194         cmpib,=,n       0,t1,.Lcopy_loop_16_start
195 20:     ldb,ma  1(srcspc,src),t1
196 21:     stb,ma  t1,1(dstspc,dst)
197         b       .Lalign_loop64
198         ldo     -1(len),len
199
200         ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
201         ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
202
203 .Lcopy_loop_16_start:
204         ldi     31,t0
205 .Lcopy_loop_16:
206         cmpb,COND(>>=),n t0,len,.Lword_loop
207
208 10:     ldd     0(srcspc,src),t1
209 11:     ldd     8(srcspc,src),t2
210         ldo     16(src),src
211 12:     std,ma  t1,8(dstspc,dst)
212 13:     std,ma  t2,8(dstspc,dst)
213 14:     ldd     0(srcspc,src),t1
214 15:     ldd     8(srcspc,src),t2
215         ldo     16(src),src
216 16:     std,ma  t1,8(dstspc,dst)
217 17:     std,ma  t2,8(dstspc,dst)
218
219         ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
220         ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy16_fault)
221         ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
222         ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
223         ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
224         ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy16_fault)
225         ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
226         ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
227
228         b       .Lcopy_loop_16
229         ldo     -32(len),len
230
231 .Lword_loop:
232         cmpib,COND(>>=),n 3,len,.Lbyte_loop
233 20:     ldw,ma  4(srcspc,src),t1
234 21:     stw,ma  t1,4(dstspc,dst)
235         b       .Lword_loop
236         ldo     -4(len),len
237
238         ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
239         ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
240
241 #endif /* CONFIG_64BIT */
242
243         /* loop until we are 32-bit aligned */
244 .Lalign_loop32:
245         extru   dst,31,2,t1
246         cmpib,=,n       0,t1,.Lcopy_loop_8
247 20:     ldb,ma  1(srcspc,src),t1
248 21:     stb,ma  t1,1(dstspc,dst)
249         b       .Lalign_loop32
250         ldo     -1(len),len
251
252         ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
253         ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
254
255
256 .Lcopy_loop_8:
257         cmpib,COND(>>=),n 15,len,.Lbyte_loop
258
259 10:     ldw     0(srcspc,src),t1
260 11:     ldw     4(srcspc,src),t2
261 12:     stw,ma  t1,4(dstspc,dst)
262 13:     stw,ma  t2,4(dstspc,dst)
263 14:     ldw     8(srcspc,src),t1
264 15:     ldw     12(srcspc,src),t2
265         ldo     16(src),src
266 16:     stw,ma  t1,4(dstspc,dst)
267 17:     stw,ma  t2,4(dstspc,dst)
268
269         ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
270         ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy8_fault)
271         ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
272         ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
273         ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
274         ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy8_fault)
275         ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
276         ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
277
278         b       .Lcopy_loop_8
279         ldo     -16(len),len
280
281 .Lbyte_loop:
282         cmpclr,COND(<>) len,%r0,%r0
283         b,n     .Lcopy_done
284 20:     ldb     0(srcspc,src),t1
285         ldo     1(src),src
286 21:     stb,ma  t1,1(dstspc,dst)
287         b       .Lbyte_loop
288         ldo     -1(len),len
289
290         ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
291         ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
292
293 .Lcopy_done:
294         bv      %r0(%r2)
295         sub     end,dst,ret0
296
297
298         /* src and dst are not aligned the same way. */
299         /* need to go the hard way */
300 .Lunaligned_copy:
301         /* align until dst is 32bit-word-aligned */
302         extru   dst,31,2,t1
303         cmpib,=,n       0,t1,.Lcopy_dstaligned
304 20:     ldb     0(srcspc,src),t1
305         ldo     1(src),src
306 21:     stb,ma  t1,1(dstspc,dst)
307         b       .Lunaligned_copy
308         ldo     -1(len),len
309
310         ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
311         ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
312
313 .Lcopy_dstaligned:
314
315         /* store src, dst and len in safe place */
316         copy    src,save_src
317         copy    dst,save_dst
318         copy    len,save_len
319
320         /* len now needs give number of words to copy */
321         SHRREG  len,2,len
322
323         /*
324          * Copy from a not-aligned src to an aligned dst using shifts.
325          * Handles 4 words per loop.
326          */
327
328         depw,z src,28,2,t0
329         subi 32,t0,t0
330         mtsar t0
331         extru len,31,2,t0
332         cmpib,= 2,t0,.Lcase2
333         /* Make src aligned by rounding it down.  */
334         depi 0,31,2,src
335
336         cmpiclr,<> 3,t0,%r0
337         b,n .Lcase3
338         cmpiclr,<> 1,t0,%r0
339         b,n .Lcase1
340 .Lcase0:
341         cmpb,COND(=) %r0,len,.Lcda_finish
342         nop
343
344 1:      ldw,ma 4(srcspc,src), a3
345         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
346 1:      ldw,ma 4(srcspc,src), a0
347         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
348         b,n .Ldo3
349 .Lcase1:
350 1:      ldw,ma 4(srcspc,src), a2
351         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
352 1:      ldw,ma 4(srcspc,src), a3
353         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
354         ldo -1(len),len
355         cmpb,COND(=),n %r0,len,.Ldo0
356 .Ldo4:
357 1:      ldw,ma 4(srcspc,src), a0
358         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
359         shrpw a2, a3, %sar, t0
360 1:      stw,ma t0, 4(dstspc,dst)
361         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
362 .Ldo3:
363 1:      ldw,ma 4(srcspc,src), a1
364         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
365         shrpw a3, a0, %sar, t0
366 1:      stw,ma t0, 4(dstspc,dst)
367         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
368 .Ldo2:
369 1:      ldw,ma 4(srcspc,src), a2
370         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
371         shrpw a0, a1, %sar, t0
372 1:      stw,ma t0, 4(dstspc,dst)
373         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
374 .Ldo1:
375 1:      ldw,ma 4(srcspc,src), a3
376         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
377         shrpw a1, a2, %sar, t0
378 1:      stw,ma t0, 4(dstspc,dst)
379         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
380         ldo -4(len),len
381         cmpb,COND(<>) %r0,len,.Ldo4
382         nop
383 .Ldo0:
384         shrpw a2, a3, %sar, t0
385 1:      stw,ma t0, 4(dstspc,dst)
386         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
387
388 .Lcda_rdfault:
389 .Lcda_finish:
390         /* calculate new src, dst and len and jump to byte-copy loop */
391         sub     dst,save_dst,t0
392         add     save_src,t0,src
393         b       .Lbyte_loop
394         sub     save_len,t0,len
395
396 .Lcase3:
397 1:      ldw,ma 4(srcspc,src), a0
398         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
399 1:      ldw,ma 4(srcspc,src), a1
400         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
401         b .Ldo2
402         ldo 1(len),len
403 .Lcase2:
404 1:      ldw,ma 4(srcspc,src), a1
405         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
406 1:      ldw,ma 4(srcspc,src), a2
407         ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
408         b .Ldo1
409         ldo 2(len),len
410
411
412         /* fault exception fixup handlers: */
413 #ifdef CONFIG_64BIT
414 .Lcopy16_fault:
415         b       .Lcopy_done
416 10:     std,ma  t1,8(dstspc,dst)
417         ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
418 #endif
419
420 .Lcopy8_fault:
421         b       .Lcopy_done
422 10:     stw,ma  t1,4(dstspc,dst)
423         ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
424 ENDPROC_CFI(pa_memcpy)
425
426         .end