Merge branch 'for-4.15/hyperv' into for-linus
[linux-block.git] / arch / sparc / lib / NG4memcpy.S
1 /* NG4memcpy.S: Niagara-4 optimized memcpy.
2  *
3  * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
4  */
5
6 #ifdef __KERNEL__
7 #include <linux/linkage.h>
8 #include <asm/visasm.h>
9 #include <asm/asi.h>
10 #define GLOBAL_SPARE    %g7
11 #else
12 #define ASI_BLK_INIT_QUAD_LDD_P 0xe2
13 #define FPRS_FEF  0x04
14
15 /* On T4 it is very expensive to access ASRs like %fprs and
16  * %asi, avoiding a read or a write can save ~50 cycles.
17  */
18 #define FPU_ENTER                       \
19         rd      %fprs, %o5;             \
20         andcc   %o5, FPRS_FEF, %g0;     \
21         be,a,pn %icc, 999f;             \
22          wr     %g0, FPRS_FEF, %fprs;   \
23         999:
24
25 #ifdef MEMCPY_DEBUG
26 #define VISEntryHalf FPU_ENTER; \
27                      clr %g1; clr %g2; clr %g3; clr %g5; subcc %g0, %g0, %g0;
28 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
29 #else
30 #define VISEntryHalf FPU_ENTER
31 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
32 #endif
33
34 #define GLOBAL_SPARE    %g5
35 #endif
36
37 #ifndef STORE_ASI
38 #ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
39 #define STORE_ASI       ASI_BLK_INIT_QUAD_LDD_P
40 #else
41 #define STORE_ASI       0x80            /* ASI_P */
42 #endif
43 #endif
44
45 #if !defined(EX_LD) && !defined(EX_ST)
46 #define NON_USER_COPY
47 #endif
48
49 #ifndef EX_LD
50 #define EX_LD(x,y)      x
51 #endif
52 #ifndef EX_LD_FP
53 #define EX_LD_FP(x,y)   x
54 #endif
55
56 #ifndef EX_ST
57 #define EX_ST(x,y)      x
58 #endif
59 #ifndef EX_ST_FP
60 #define EX_ST_FP(x,y)   x
61 #endif
62
63
64 #ifndef LOAD
65 #define LOAD(type,addr,dest)    type [addr], dest
66 #endif
67
68 #ifndef STORE
69 #ifndef MEMCPY_DEBUG
70 #define STORE(type,src,addr)    type src, [addr]
71 #else
72 #define STORE(type,src,addr)    type##a src, [addr] %asi
73 #endif
74 #endif
75
76 #ifndef STORE_INIT
77 #define STORE_INIT(src,addr)    stxa src, [addr] STORE_ASI
78 #endif
79
80 #ifndef FUNC_NAME
81 #define FUNC_NAME       NG4memcpy
82 #endif
83 #ifndef PREAMBLE
84 #define PREAMBLE
85 #endif
86
87 #ifndef XCC
88 #define XCC xcc
89 #endif
90
91         .register       %g2,#scratch
92         .register       %g3,#scratch
93
94         .text
95 #ifndef EX_RETVAL
96 #define EX_RETVAL(x)    x
97 #endif
98         .align          64
99
100         .globl  FUNC_NAME
101         .type   FUNC_NAME,#function
102 FUNC_NAME:      /* %o0=dst, %o1=src, %o2=len */
103 #ifdef MEMCPY_DEBUG
104         wr              %g0, 0x80, %asi
105 #endif
106         srlx            %o2, 31, %g2
107         cmp             %g2, 0
108         tne             %XCC, 5
109         PREAMBLE
110         mov             %o0, %o3
111         brz,pn          %o2, .Lexit
112          cmp            %o2, 3
113         ble,pn          %icc, .Ltiny
114          cmp            %o2, 19
115         ble,pn          %icc, .Lsmall
116          or             %o0, %o1, %g2
117         cmp             %o2, 128
118         bl,pn           %icc, .Lmedium
119          nop
120
121 .Llarge:/* len >= 0x80 */
122         /* First get dest 8 byte aligned.  */
123         sub             %g0, %o0, %g1
124         and             %g1, 0x7, %g1
125         brz,pt          %g1, 51f
126          sub            %o2, %g1, %o2
127
128
129 1:      EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
130         add             %o1, 1, %o1
131         subcc           %g1, 1, %g1
132         add             %o0, 1, %o0
133         bne,pt          %icc, 1b
134          EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
135
136 51:     LOAD(prefetch, %o1 + 0x040, #n_reads_strong)
137         LOAD(prefetch, %o1 + 0x080, #n_reads_strong)
138         LOAD(prefetch, %o1 + 0x0c0, #n_reads_strong)
139         LOAD(prefetch, %o1 + 0x100, #n_reads_strong)
140         LOAD(prefetch, %o1 + 0x140, #n_reads_strong)
141         LOAD(prefetch, %o1 + 0x180, #n_reads_strong)
142         LOAD(prefetch, %o1 + 0x1c0, #n_reads_strong)
143         LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
144
145         /* Check if we can use the straight fully aligned
146          * loop, or we require the alignaddr/faligndata variant.
147          */
148         andcc           %o1, 0x7, %o5
149         bne,pn          %icc, .Llarge_src_unaligned
150          sub            %g0, %o0, %g1
151
152         /* Legitimize the use of initializing stores by getting dest
153          * to be 64-byte aligned.
154          */
155         and             %g1, 0x3f, %g1
156         brz,pt          %g1, .Llarge_aligned
157          sub            %o2, %g1, %o2
158
159 1:      EX_LD(LOAD(ldx, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
160         add             %o1, 8, %o1
161         subcc           %g1, 8, %g1
162         add             %o0, 8, %o0
163         bne,pt          %icc, 1b
164          EX_ST(STORE(stx, %g2, %o0 - 0x08), memcpy_retl_o2_plus_g1_plus_8)
165
166 .Llarge_aligned:
167         /* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
168         andn            %o2, 0x3f, %o4
169         sub             %o2, %o4, %o2
170
171 1:      EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o4)
172         add             %o1, 0x40, %o1
173         EX_LD(LOAD(ldx, %o1 - 0x38, %g2), memcpy_retl_o2_plus_o4)
174         subcc           %o4, 0x40, %o4
175         EX_LD(LOAD(ldx, %o1 - 0x30, %g3), memcpy_retl_o2_plus_o4_plus_64)
176         EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE), memcpy_retl_o2_plus_o4_plus_64)
177         EX_LD(LOAD(ldx, %o1 - 0x20, %o5), memcpy_retl_o2_plus_o4_plus_64)
178         EX_ST(STORE_INIT(%g1, %o0), memcpy_retl_o2_plus_o4_plus_64)
179         add             %o0, 0x08, %o0
180         EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_56)
181         add             %o0, 0x08, %o0
182         EX_LD(LOAD(ldx, %o1 - 0x18, %g2), memcpy_retl_o2_plus_o4_plus_48)
183         EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_48)
184         add             %o0, 0x08, %o0
185         EX_LD(LOAD(ldx, %o1 - 0x10, %g3), memcpy_retl_o2_plus_o4_plus_40)
186         EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_40)
187         add             %o0, 0x08, %o0
188         EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE), memcpy_retl_o2_plus_o4_plus_32)
189         EX_ST(STORE_INIT(%o5, %o0), memcpy_retl_o2_plus_o4_plus_32)
190         add             %o0, 0x08, %o0
191         EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_24)
192         add             %o0, 0x08, %o0
193         EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_16)
194         add             %o0, 0x08, %o0
195         EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_8)
196         add             %o0, 0x08, %o0
197         bne,pt          %icc, 1b
198          LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
199
200         membar          #StoreLoad | #StoreStore
201
202         brz,pn          %o2, .Lexit
203          cmp            %o2, 19
204         ble,pn          %icc, .Lsmall_unaligned
205          nop
206         ba,a,pt         %icc, .Lmedium_noprefetch
207
208 .Lexit: retl
209          mov            EX_RETVAL(%o3), %o0
210
211 .Llarge_src_unaligned:
212 #ifdef NON_USER_COPY
213         VISEntryHalfFast(.Lmedium_vis_entry_fail)
214 #else
215         VISEntryHalf
216 #endif
217         andn            %o2, 0x3f, %o4
218         sub             %o2, %o4, %o2
219         alignaddr       %o1, %g0, %g1
220         add             %o1, %o4, %o1
221         EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0), memcpy_retl_o2_plus_o4)
222 1:      EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2), memcpy_retl_o2_plus_o4)
223         subcc           %o4, 0x40, %o4
224         EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4), memcpy_retl_o2_plus_o4_plus_64)
225         EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6), memcpy_retl_o2_plus_o4_plus_64)
226         EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8), memcpy_retl_o2_plus_o4_plus_64)
227         EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10), memcpy_retl_o2_plus_o4_plus_64)
228         EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12), memcpy_retl_o2_plus_o4_plus_64)
229         EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14), memcpy_retl_o2_plus_o4_plus_64)
230         faligndata      %f0, %f2, %f16
231         EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0), memcpy_retl_o2_plus_o4_plus_64)
232         faligndata      %f2, %f4, %f18
233         add             %g1, 0x40, %g1
234         faligndata      %f4, %f6, %f20
235         faligndata      %f6, %f8, %f22
236         faligndata      %f8, %f10, %f24
237         faligndata      %f10, %f12, %f26
238         faligndata      %f12, %f14, %f28
239         faligndata      %f14, %f0, %f30
240         EX_ST_FP(STORE(std, %f16, %o0 + 0x00), memcpy_retl_o2_plus_o4_plus_64)
241         EX_ST_FP(STORE(std, %f18, %o0 + 0x08), memcpy_retl_o2_plus_o4_plus_56)
242         EX_ST_FP(STORE(std, %f20, %o0 + 0x10), memcpy_retl_o2_plus_o4_plus_48)
243         EX_ST_FP(STORE(std, %f22, %o0 + 0x18), memcpy_retl_o2_plus_o4_plus_40)
244         EX_ST_FP(STORE(std, %f24, %o0 + 0x20), memcpy_retl_o2_plus_o4_plus_32)
245         EX_ST_FP(STORE(std, %f26, %o0 + 0x28), memcpy_retl_o2_plus_o4_plus_24)
246         EX_ST_FP(STORE(std, %f28, %o0 + 0x30), memcpy_retl_o2_plus_o4_plus_16)
247         EX_ST_FP(STORE(std, %f30, %o0 + 0x38), memcpy_retl_o2_plus_o4_plus_8)
248         add             %o0, 0x40, %o0
249         bne,pt          %icc, 1b
250          LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
251 #ifdef NON_USER_COPY
252         VISExitHalfFast
253 #else
254         VISExitHalf
255 #endif
256         brz,pn          %o2, .Lexit
257          cmp            %o2, 19
258         ble,pn          %icc, .Lsmall_unaligned
259          nop
260         ba,a,pt         %icc, .Lmedium_unaligned
261
262 #ifdef NON_USER_COPY
263 .Lmedium_vis_entry_fail:
264          or             %o0, %o1, %g2
265 #endif
266 .Lmedium:
267         LOAD(prefetch, %o1 + 0x40, #n_reads_strong)
268         andcc           %g2, 0x7, %g0
269         bne,pn          %icc, .Lmedium_unaligned
270          nop
271 .Lmedium_noprefetch:
272         andncc          %o2, 0x20 - 1, %o5
273         be,pn           %icc, 2f
274          sub            %o2, %o5, %o2
275 1:      EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
276         EX_LD(LOAD(ldx, %o1 + 0x08, %g2), memcpy_retl_o2_plus_o5)
277         EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE), memcpy_retl_o2_plus_o5)
278         EX_LD(LOAD(ldx, %o1 + 0x18, %o4), memcpy_retl_o2_plus_o5)
279         add             %o1, 0x20, %o1
280         subcc           %o5, 0x20, %o5
281         EX_ST(STORE(stx, %g1, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_32)
282         EX_ST(STORE(stx, %g2, %o0 + 0x08), memcpy_retl_o2_plus_o5_plus_24)
283         EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_24)
284         EX_ST(STORE(stx, %o4, %o0 + 0x18), memcpy_retl_o2_plus_o5_plus_8)
285         bne,pt          %icc, 1b
286          add            %o0, 0x20, %o0
287 2:      andcc           %o2, 0x18, %o5
288         be,pt           %icc, 3f
289          sub            %o2, %o5, %o2
290
291 1:      EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
292         add             %o1, 0x08, %o1
293         add             %o0, 0x08, %o0
294         subcc           %o5, 0x08, %o5
295         bne,pt          %icc, 1b
296          EX_ST(STORE(stx, %g1, %o0 - 0x08), memcpy_retl_o2_plus_o5_plus_8)
297 3:      brz,pt          %o2, .Lexit
298          cmp            %o2, 0x04
299         bl,pn           %icc, .Ltiny
300          nop
301         EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2)
302         add             %o1, 0x04, %o1
303         add             %o0, 0x04, %o0
304         subcc           %o2, 0x04, %o2
305         bne,pn          %icc, .Ltiny
306          EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_4)
307         ba,a,pt         %icc, .Lexit
308 .Lmedium_unaligned:
309         /* First get dest 8 byte aligned.  */
310         sub             %g0, %o0, %g1
311         and             %g1, 0x7, %g1
312         brz,pt          %g1, 2f
313          sub            %o2, %g1, %o2
314
315 1:      EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
316         add             %o1, 1, %o1
317         subcc           %g1, 1, %g1
318         add             %o0, 1, %o0
319         bne,pt          %icc, 1b
320          EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
321 2:
322         and             %o1, 0x7, %g1
323         brz,pn          %g1, .Lmedium_noprefetch
324          sll            %g1, 3, %g1
325         mov             64, %g2
326         sub             %g2, %g1, %g2
327         andn            %o1, 0x7, %o1
328         EX_LD(LOAD(ldx, %o1 + 0x00, %o4), memcpy_retl_o2)
329         sllx            %o4, %g1, %o4
330         andn            %o2, 0x08 - 1, %o5
331         sub             %o2, %o5, %o2
332 1:      EX_LD(LOAD(ldx, %o1 + 0x08, %g3), memcpy_retl_o2_plus_o5)
333         add             %o1, 0x08, %o1
334         subcc           %o5, 0x08, %o5
335         srlx            %g3, %g2, GLOBAL_SPARE
336         or              GLOBAL_SPARE, %o4, GLOBAL_SPARE
337         EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_8)
338         add             %o0, 0x08, %o0
339         bne,pt          %icc, 1b
340          sllx           %g3, %g1, %o4
341         srl             %g1, 3, %g1
342         add             %o1, %g1, %o1
343         brz,pn          %o2, .Lexit
344          nop
345         ba,pt           %icc, .Lsmall_unaligned
346
347 .Ltiny:
348         EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
349         subcc           %o2, 1, %o2
350         be,pn           %icc, .Lexit
351          EX_ST(STORE(stb, %g1, %o0 + 0x00), memcpy_retl_o2_plus_1)
352         EX_LD(LOAD(ldub, %o1 + 0x01, %g1), memcpy_retl_o2)
353         subcc           %o2, 1, %o2
354         be,pn           %icc, .Lexit
355          EX_ST(STORE(stb, %g1, %o0 + 0x01), memcpy_retl_o2_plus_1)
356         EX_LD(LOAD(ldub, %o1 + 0x02, %g1), memcpy_retl_o2)
357         ba,pt           %icc, .Lexit
358          EX_ST(STORE(stb, %g1, %o0 + 0x02), memcpy_retl_o2)
359
360 .Lsmall:
361         andcc           %g2, 0x3, %g0
362         bne,pn          %icc, .Lsmall_unaligned
363          andn           %o2, 0x4 - 1, %o5
364         sub             %o2, %o5, %o2
365 1:
366         EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
367         add             %o1, 0x04, %o1
368         subcc           %o5, 0x04, %o5
369         add             %o0, 0x04, %o0
370         bne,pt          %icc, 1b
371          EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_o5_plus_4)
372         brz,pt          %o2, .Lexit
373          nop
374         ba,a,pt         %icc, .Ltiny
375
376 .Lsmall_unaligned:
377 1:      EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
378         add             %o1, 1, %o1
379         add             %o0, 1, %o0
380         subcc           %o2, 1, %o2
381         bne,pt          %icc, 1b
382          EX_ST(STORE(stb, %g1, %o0 - 0x01), memcpy_retl_o2_plus_1)
383         ba,a,pt         %icc, .Lexit
384          nop
385         .size           FUNC_NAME, .-FUNC_NAME