1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* NG4memcpy.S: Niagara-4 optimized memcpy.
4 * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
8 #include <linux/linkage.h>
9 #include <asm/visasm.h>
11 #define GLOBAL_SPARE %g7
13 #define ASI_BLK_INIT_QUAD_LDD_P 0xe2
16 /* On T4 it is very expensive to access ASRs like %fprs and
17 * %asi, avoiding a read or a write can save ~50 cycles.
21 andcc %o5, FPRS_FEF, %g0; \
23 wr %g0, FPRS_FEF, %fprs; \
27 #define VISEntryHalf FPU_ENTER; \
28 clr %g1; clr %g2; clr %g3; clr %g5; subcc %g0, %g0, %g0;
29 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
31 #define VISEntryHalf FPU_ENTER
32 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
35 #define GLOBAL_SPARE %g5
39 #ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
40 #define STORE_ASI ASI_BLK_INIT_QUAD_LDD_P
42 #define STORE_ASI 0x80 /* ASI_P */
46 #if !defined(EX_LD) && !defined(EX_ST)
54 #define EX_LD_FP(x,y) x
61 #define EX_ST_FP(x,y) x
66 #define LOAD(type,addr,dest) type [addr], dest
71 #define STORE(type,src,addr) type src, [addr]
73 #define STORE(type,src,addr) type##a src, [addr] %asi
78 #define STORE_INIT(src,addr) stxa src, [addr] STORE_ASI
82 #define FUNC_NAME NG4memcpy
92 .register %g2,#scratch
93 .register %g3,#scratch
97 #define EX_RETVAL(x) x
102 .type FUNC_NAME,#function
103 FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
122 .Llarge:/* len >= 0x80 */
123 /* First get dest 8 byte aligned. */
130 1: EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
135 EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
137 51: LOAD(prefetch, %o1 + 0x040, #n_reads_strong)
138 LOAD(prefetch, %o1 + 0x080, #n_reads_strong)
139 LOAD(prefetch, %o1 + 0x0c0, #n_reads_strong)
140 LOAD(prefetch, %o1 + 0x100, #n_reads_strong)
141 LOAD(prefetch, %o1 + 0x140, #n_reads_strong)
142 LOAD(prefetch, %o1 + 0x180, #n_reads_strong)
143 LOAD(prefetch, %o1 + 0x1c0, #n_reads_strong)
144 LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
146 /* Check if we can use the straight fully aligned
147 * loop, or we require the alignaddr/faligndata variant.
150 bne,pn %icc, .Llarge_src_unaligned
153 /* Legitimize the use of initializing stores by getting dest
154 * to be 64-byte aligned.
157 brz,pt %g1, .Llarge_aligned
160 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
165 EX_ST(STORE(stx, %g2, %o0 - 0x08), memcpy_retl_o2_plus_g1_plus_8)
168 /* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
172 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o4)
174 EX_LD(LOAD(ldx, %o1 - 0x38, %g2), memcpy_retl_o2_plus_o4)
176 EX_LD(LOAD(ldx, %o1 - 0x30, %g3), memcpy_retl_o2_plus_o4_plus_64)
177 EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE), memcpy_retl_o2_plus_o4_plus_64)
178 EX_LD(LOAD(ldx, %o1 - 0x20, %o5), memcpy_retl_o2_plus_o4_plus_64)
179 EX_ST(STORE_INIT(%g1, %o0), memcpy_retl_o2_plus_o4_plus_64)
181 EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_56)
183 EX_LD(LOAD(ldx, %o1 - 0x18, %g2), memcpy_retl_o2_plus_o4_plus_48)
184 EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_48)
186 EX_LD(LOAD(ldx, %o1 - 0x10, %g3), memcpy_retl_o2_plus_o4_plus_40)
187 EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_40)
189 EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE), memcpy_retl_o2_plus_o4_plus_32)
190 EX_ST(STORE_INIT(%o5, %o0), memcpy_retl_o2_plus_o4_plus_32)
192 EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_24)
194 EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_16)
196 EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_8)
199 LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
201 membar #StoreLoad | #StoreStore
205 ble,pn %icc, .Lsmall_unaligned
207 ba,a,pt %icc, .Lmedium_noprefetch
210 mov EX_RETVAL(%o3), %o0
212 .Llarge_src_unaligned:
214 VISEntryHalfFast(.Lmedium_vis_entry_fail)
220 alignaddr %o1, %g0, %g1
222 EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0), memcpy_retl_o2_plus_o4)
223 1: EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2), memcpy_retl_o2_plus_o4)
225 EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4), memcpy_retl_o2_plus_o4_plus_64)
226 EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6), memcpy_retl_o2_plus_o4_plus_64)
227 EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8), memcpy_retl_o2_plus_o4_plus_64)
228 EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10), memcpy_retl_o2_plus_o4_plus_64)
229 EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12), memcpy_retl_o2_plus_o4_plus_64)
230 EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14), memcpy_retl_o2_plus_o4_plus_64)
231 faligndata %f0, %f2, %f16
232 EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0), memcpy_retl_o2_plus_o4_plus_64)
233 faligndata %f2, %f4, %f18
235 faligndata %f4, %f6, %f20
236 faligndata %f6, %f8, %f22
237 faligndata %f8, %f10, %f24
238 faligndata %f10, %f12, %f26
239 faligndata %f12, %f14, %f28
240 faligndata %f14, %f0, %f30
241 EX_ST_FP(STORE(std, %f16, %o0 + 0x00), memcpy_retl_o2_plus_o4_plus_64)
242 EX_ST_FP(STORE(std, %f18, %o0 + 0x08), memcpy_retl_o2_plus_o4_plus_56)
243 EX_ST_FP(STORE(std, %f20, %o0 + 0x10), memcpy_retl_o2_plus_o4_plus_48)
244 EX_ST_FP(STORE(std, %f22, %o0 + 0x18), memcpy_retl_o2_plus_o4_plus_40)
245 EX_ST_FP(STORE(std, %f24, %o0 + 0x20), memcpy_retl_o2_plus_o4_plus_32)
246 EX_ST_FP(STORE(std, %f26, %o0 + 0x28), memcpy_retl_o2_plus_o4_plus_24)
247 EX_ST_FP(STORE(std, %f28, %o0 + 0x30), memcpy_retl_o2_plus_o4_plus_16)
248 EX_ST_FP(STORE(std, %f30, %o0 + 0x38), memcpy_retl_o2_plus_o4_plus_8)
251 LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
259 ble,pn %icc, .Lsmall_unaligned
261 ba,a,pt %icc, .Lmedium_unaligned
264 .Lmedium_vis_entry_fail:
268 LOAD(prefetch, %o1 + 0x40, #n_reads_strong)
270 bne,pn %icc, .Lmedium_unaligned
273 andncc %o2, 0x20 - 1, %o5
276 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
277 EX_LD(LOAD(ldx, %o1 + 0x08, %g2), memcpy_retl_o2_plus_o5)
278 EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE), memcpy_retl_o2_plus_o5)
279 EX_LD(LOAD(ldx, %o1 + 0x18, %o4), memcpy_retl_o2_plus_o5)
282 EX_ST(STORE(stx, %g1, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_32)
283 EX_ST(STORE(stx, %g2, %o0 + 0x08), memcpy_retl_o2_plus_o5_plus_24)
284 EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_24)
285 EX_ST(STORE(stx, %o4, %o0 + 0x18), memcpy_retl_o2_plus_o5_plus_8)
288 2: andcc %o2, 0x18, %o5
292 1: EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
297 EX_ST(STORE(stx, %g1, %o0 - 0x08), memcpy_retl_o2_plus_o5_plus_8)
298 3: brz,pt %o2, .Lexit
302 EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2)
307 EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_4)
310 /* First get dest 8 byte aligned. */
316 1: EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
321 EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
324 brz,pn %g1, .Lmedium_noprefetch
329 EX_LD(LOAD(ldx, %o1 + 0x00, %o4), memcpy_retl_o2)
331 andn %o2, 0x08 - 1, %o5
333 1: EX_LD(LOAD(ldx, %o1 + 0x08, %g3), memcpy_retl_o2_plus_o5)
336 srlx %g3, %g2, GLOBAL_SPARE
337 or GLOBAL_SPARE, %o4, GLOBAL_SPARE
338 EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_8)
346 ba,pt %icc, .Lsmall_unaligned
349 EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
352 EX_ST(STORE(stb, %g1, %o0 + 0x00), memcpy_retl_o2_plus_1)
353 EX_LD(LOAD(ldub, %o1 + 0x01, %g1), memcpy_retl_o2)
356 EX_ST(STORE(stb, %g1, %o0 + 0x01), memcpy_retl_o2_plus_1)
357 EX_LD(LOAD(ldub, %o1 + 0x02, %g1), memcpy_retl_o2)
359 EX_ST(STORE(stb, %g1, %o0 + 0x02), memcpy_retl_o2)
363 bne,pn %icc, .Lsmall_unaligned
364 andn %o2, 0x4 - 1, %o5
367 EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
372 EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_o5_plus_4)
378 1: EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
383 EX_ST(STORE(stb, %g1, %o0 - 0x01), memcpy_retl_o2_plus_1)
386 .size FUNC_NAME, .-FUNC_NAME