1 /* NG4memcpy.S: Niagara-4 optimized memcpy.
3 * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
7 #include <linux/linkage.h>
8 #include <asm/visasm.h>
10 #define GLOBAL_SPARE %g7
12 #define ASI_BLK_INIT_QUAD_LDD_P 0xe2
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.
20 andcc %o5, FPRS_FEF, %g0; \
22 wr %g0, FPRS_FEF, %fprs; \
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
30 #define VISEntryHalf FPU_ENTER
31 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
34 #define GLOBAL_SPARE %g5
38 #ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
39 #define STORE_ASI ASI_BLK_INIT_QUAD_LDD_P
41 #define STORE_ASI 0x80 /* ASI_P */
45 #if !defined(EX_LD) && !defined(EX_ST)
53 #define EX_LD_FP(x,y) x
60 #define EX_ST_FP(x,y) x
65 #define LOAD(type,addr,dest) type [addr], dest
70 #define STORE(type,src,addr) type src, [addr]
72 #define STORE(type,src,addr) type##a src, [addr] %asi
77 #define STORE_INIT(src,addr) stxa src, [addr] STORE_ASI
81 #define FUNC_NAME NG4memcpy
91 .register %g2,#scratch
92 .register %g3,#scratch
96 #define EX_RETVAL(x) x
101 .type FUNC_NAME,#function
102 FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
121 .Llarge:/* len >= 0x80 */
122 /* First get dest 8 byte aligned. */
129 1: EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
134 EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
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)
145 /* Check if we can use the straight fully aligned
146 * loop, or we require the alignaddr/faligndata variant.
149 bne,pn %icc, .Llarge_src_unaligned
152 /* Legitimize the use of initializing stores by getting dest
153 * to be 64-byte aligned.
156 brz,pt %g1, .Llarge_aligned
159 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
164 EX_ST(STORE(stx, %g2, %o0 - 0x08), memcpy_retl_o2_plus_g1_plus_8)
167 /* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
171 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o4)
173 EX_LD(LOAD(ldx, %o1 - 0x38, %g2), memcpy_retl_o2_plus_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)
180 EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_56)
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)
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)
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)
191 EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_24)
193 EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_16)
195 EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_8)
198 LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
200 membar #StoreLoad | #StoreStore
204 ble,pn %icc, .Lsmall_unaligned
206 ba,a,pt %icc, .Lmedium_noprefetch
209 mov EX_RETVAL(%o3), %o0
211 .Llarge_src_unaligned:
213 VISEntryHalfFast(.Lmedium_vis_entry_fail)
219 alignaddr %o1, %g0, %g1
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)
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
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)
250 LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
258 ble,pn %icc, .Lsmall_unaligned
260 ba,a,pt %icc, .Lmedium_unaligned
263 .Lmedium_vis_entry_fail:
267 LOAD(prefetch, %o1 + 0x40, #n_reads_strong)
269 bne,pn %icc, .Lmedium_unaligned
272 andncc %o2, 0x20 - 1, %o5
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)
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)
287 2: andcc %o2, 0x18, %o5
291 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
296 EX_ST(STORE(stx, %g1, %o0 - 0x08), memcpy_retl_o2_plus_o5_plus_8)
297 3: brz,pt %o2, .Lexit
301 EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2)
306 EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_4)
309 /* First get dest 8 byte aligned. */
315 1: EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
320 EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
323 brz,pn %g1, .Lmedium_noprefetch
328 EX_LD(LOAD(ldx, %o1 + 0x00, %o4), memcpy_retl_o2)
330 andn %o2, 0x08 - 1, %o5
332 1: EX_LD(LOAD(ldx, %o1 + 0x08, %g3), memcpy_retl_o2_plus_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)
345 ba,pt %icc, .Lsmall_unaligned
348 EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
351 EX_ST(STORE(stb, %g1, %o0 + 0x00), memcpy_retl_o2_plus_1)
352 EX_LD(LOAD(ldub, %o1 + 0x01, %g1), memcpy_retl_o2)
355 EX_ST(STORE(stb, %g1, %o0 + 0x01), memcpy_retl_o2_plus_1)
356 EX_LD(LOAD(ldub, %o1 + 0x02, %g1), memcpy_retl_o2)
358 EX_ST(STORE(stb, %g1, %o0 + 0x02), memcpy_retl_o2)
362 bne,pn %icc, .Lsmall_unaligned
363 andn %o2, 0x4 - 1, %o5
366 EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
371 EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_o5_plus_4)
377 1: EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
382 EX_ST(STORE(stb, %g1, %o0 - 0x01), memcpy_retl_o2_plus_1)
385 .size FUNC_NAME, .-FUNC_NAME