Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /* NG4memcpy.S: Niagara-4 optimized memcpy.
0003  *
0004  * Copyright (C) 2012 David S. Miller (davem@davemloft.net)
0005  */
0006 
0007 #ifdef __KERNEL__
0008 #include <linux/linkage.h>
0009 #include <asm/visasm.h>
0010 #include <asm/asi.h>
0011 #define GLOBAL_SPARE    %g7
0012 #else
0013 #define ASI_BLK_INIT_QUAD_LDD_P 0xe2
0014 #define FPRS_FEF  0x04
0015 
0016 /* On T4 it is very expensive to access ASRs like %fprs and
0017  * %asi, avoiding a read or a write can save ~50 cycles.
0018  */
0019 #define FPU_ENTER           \
0020     rd  %fprs, %o5;     \
0021     andcc   %o5, FPRS_FEF, %g0; \
0022     be,a,pn %icc, 999f;     \
0023      wr %g0, FPRS_FEF, %fprs;   \
0024     999:
0025 
0026 #ifdef MEMCPY_DEBUG
0027 #define VISEntryHalf FPU_ENTER; \
0028              clr %g1; clr %g2; clr %g3; clr %g5; subcc %g0, %g0, %g0;
0029 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
0030 #else
0031 #define VISEntryHalf FPU_ENTER
0032 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
0033 #endif
0034 
0035 #define GLOBAL_SPARE    %g5
0036 #endif
0037 
0038 #ifndef STORE_ASI
0039 #ifndef SIMULATE_NIAGARA_ON_NON_NIAGARA
0040 #define STORE_ASI   ASI_BLK_INIT_QUAD_LDD_P
0041 #else
0042 #define STORE_ASI   0x80        /* ASI_P */
0043 #endif
0044 #endif
0045 
0046 #if !defined(EX_LD) && !defined(EX_ST)
0047 #define NON_USER_COPY
0048 #endif
0049 
0050 #ifndef EX_LD
0051 #define EX_LD(x,y)  x
0052 #endif
0053 #ifndef EX_LD_FP
0054 #define EX_LD_FP(x,y)   x
0055 #endif
0056 
0057 #ifndef EX_ST
0058 #define EX_ST(x,y)  x
0059 #endif
0060 #ifndef EX_ST_FP
0061 #define EX_ST_FP(x,y)   x
0062 #endif
0063 
0064 
0065 #ifndef LOAD
0066 #define LOAD(type,addr,dest)    type [addr], dest
0067 #endif
0068 
0069 #ifndef STORE
0070 #ifndef MEMCPY_DEBUG
0071 #define STORE(type,src,addr)    type src, [addr]
0072 #else
0073 #define STORE(type,src,addr)    type##a src, [addr] %asi
0074 #endif
0075 #endif
0076 
0077 #ifndef STORE_INIT
0078 #define STORE_INIT(src,addr)    stxa src, [addr] STORE_ASI
0079 #endif
0080 
0081 #ifndef FUNC_NAME
0082 #define FUNC_NAME   NG4memcpy
0083 #endif
0084 #ifndef PREAMBLE
0085 #define PREAMBLE
0086 #endif
0087 
0088 #ifndef XCC
0089 #define XCC xcc
0090 #endif
0091 
0092     .register   %g2,#scratch
0093     .register   %g3,#scratch
0094 
0095     .text
0096 #ifndef EX_RETVAL
0097 #define EX_RETVAL(x)    x
0098 #endif
0099     .align      64
0100 
0101     .globl  FUNC_NAME
0102     .type   FUNC_NAME,#function
0103 FUNC_NAME:  /* %o0=dst, %o1=src, %o2=len */
0104 #ifdef MEMCPY_DEBUG
0105     wr      %g0, 0x80, %asi
0106 #endif
0107     srlx        %o2, 31, %g2
0108     cmp     %g2, 0
0109     tne     %XCC, 5
0110     PREAMBLE
0111     mov     %o0, %o3
0112     brz,pn      %o2, .Lexit
0113      cmp        %o2, 3
0114     ble,pn      %icc, .Ltiny
0115      cmp        %o2, 19
0116     ble,pn      %icc, .Lsmall
0117      or     %o0, %o1, %g2
0118     cmp     %o2, 128
0119     bl,pn       %icc, .Lmedium
0120      nop
0121 
0122 .Llarge:/* len >= 0x80 */
0123     /* First get dest 8 byte aligned.  */
0124     sub     %g0, %o0, %g1
0125     and     %g1, 0x7, %g1
0126     brz,pt      %g1, 51f
0127      sub        %o2, %g1, %o2
0128 
0129 
0130 1:  EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
0131     add     %o1, 1, %o1
0132     subcc       %g1, 1, %g1
0133     add     %o0, 1, %o0
0134     bne,pt      %icc, 1b
0135      EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
0136 
0137 51: LOAD(prefetch, %o1 + 0x040, #n_reads_strong)
0138     LOAD(prefetch, %o1 + 0x080, #n_reads_strong)
0139     LOAD(prefetch, %o1 + 0x0c0, #n_reads_strong)
0140     LOAD(prefetch, %o1 + 0x100, #n_reads_strong)
0141     LOAD(prefetch, %o1 + 0x140, #n_reads_strong)
0142     LOAD(prefetch, %o1 + 0x180, #n_reads_strong)
0143     LOAD(prefetch, %o1 + 0x1c0, #n_reads_strong)
0144     LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
0145 
0146     /* Check if we can use the straight fully aligned
0147      * loop, or we require the alignaddr/faligndata variant.
0148      */
0149     andcc       %o1, 0x7, %o5
0150     bne,pn      %icc, .Llarge_src_unaligned
0151      sub        %g0, %o0, %g1
0152 
0153     /* Legitimize the use of initializing stores by getting dest
0154      * to be 64-byte aligned.
0155      */
0156     and     %g1, 0x3f, %g1
0157     brz,pt      %g1, .Llarge_aligned
0158      sub        %o2, %g1, %o2
0159 
0160 1:  EX_LD(LOAD(ldx, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
0161     add     %o1, 8, %o1
0162     subcc       %g1, 8, %g1
0163     add     %o0, 8, %o0
0164     bne,pt      %icc, 1b
0165      EX_ST(STORE(stx, %g2, %o0 - 0x08), memcpy_retl_o2_plus_g1_plus_8)
0166 
0167 .Llarge_aligned:
0168     /* len >= 0x80 && src 8-byte aligned && dest 8-byte aligned */
0169     andn        %o2, 0x3f, %o4
0170     sub     %o2, %o4, %o2
0171 
0172 1:  EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o4)
0173     add     %o1, 0x40, %o1
0174     EX_LD(LOAD(ldx, %o1 - 0x38, %g2), memcpy_retl_o2_plus_o4)
0175     subcc       %o4, 0x40, %o4
0176     EX_LD(LOAD(ldx, %o1 - 0x30, %g3), memcpy_retl_o2_plus_o4_plus_64)
0177     EX_LD(LOAD(ldx, %o1 - 0x28, GLOBAL_SPARE), memcpy_retl_o2_plus_o4_plus_64)
0178     EX_LD(LOAD(ldx, %o1 - 0x20, %o5), memcpy_retl_o2_plus_o4_plus_64)
0179     EX_ST(STORE_INIT(%g1, %o0), memcpy_retl_o2_plus_o4_plus_64)
0180     add     %o0, 0x08, %o0
0181     EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_56)
0182     add     %o0, 0x08, %o0
0183     EX_LD(LOAD(ldx, %o1 - 0x18, %g2), memcpy_retl_o2_plus_o4_plus_48)
0184     EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_48)
0185     add     %o0, 0x08, %o0
0186     EX_LD(LOAD(ldx, %o1 - 0x10, %g3), memcpy_retl_o2_plus_o4_plus_40)
0187     EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_40)
0188     add     %o0, 0x08, %o0
0189     EX_LD(LOAD(ldx, %o1 - 0x08, GLOBAL_SPARE), memcpy_retl_o2_plus_o4_plus_32)
0190     EX_ST(STORE_INIT(%o5, %o0), memcpy_retl_o2_plus_o4_plus_32)
0191     add     %o0, 0x08, %o0
0192     EX_ST(STORE_INIT(%g2, %o0), memcpy_retl_o2_plus_o4_plus_24)
0193     add     %o0, 0x08, %o0
0194     EX_ST(STORE_INIT(%g3, %o0), memcpy_retl_o2_plus_o4_plus_16)
0195     add     %o0, 0x08, %o0
0196     EX_ST(STORE_INIT(GLOBAL_SPARE, %o0), memcpy_retl_o2_plus_o4_plus_8)
0197     add     %o0, 0x08, %o0
0198     bne,pt      %icc, 1b
0199      LOAD(prefetch, %o1 + 0x200, #n_reads_strong)
0200 
0201     membar      #StoreLoad | #StoreStore
0202 
0203     brz,pn      %o2, .Lexit
0204      cmp        %o2, 19
0205     ble,pn      %icc, .Lsmall_unaligned
0206      nop
0207     ba,a,pt     %icc, .Lmedium_noprefetch
0208 
0209 .Lexit: retl
0210      mov        EX_RETVAL(%o3), %o0
0211 
0212 .Llarge_src_unaligned:
0213 #ifdef NON_USER_COPY
0214     VISEntryHalfFast(.Lmedium_vis_entry_fail)
0215 #else
0216     VISEntryHalf
0217 #endif
0218     andn        %o2, 0x3f, %o4
0219     sub     %o2, %o4, %o2
0220     alignaddr   %o1, %g0, %g1
0221     add     %o1, %o4, %o1
0222     EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0), memcpy_retl_o2_plus_o4)
0223 1:  EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2), memcpy_retl_o2_plus_o4)
0224     subcc       %o4, 0x40, %o4
0225     EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4), memcpy_retl_o2_plus_o4_plus_64)
0226     EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6), memcpy_retl_o2_plus_o4_plus_64)
0227     EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8), memcpy_retl_o2_plus_o4_plus_64)
0228     EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10), memcpy_retl_o2_plus_o4_plus_64)
0229     EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12), memcpy_retl_o2_plus_o4_plus_64)
0230     EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14), memcpy_retl_o2_plus_o4_plus_64)
0231     faligndata  %f0, %f2, %f16
0232     EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0), memcpy_retl_o2_plus_o4_plus_64)
0233     faligndata  %f2, %f4, %f18
0234     add     %g1, 0x40, %g1
0235     faligndata  %f4, %f6, %f20
0236     faligndata  %f6, %f8, %f22
0237     faligndata  %f8, %f10, %f24
0238     faligndata  %f10, %f12, %f26
0239     faligndata  %f12, %f14, %f28
0240     faligndata  %f14, %f0, %f30
0241     EX_ST_FP(STORE(std, %f16, %o0 + 0x00), memcpy_retl_o2_plus_o4_plus_64)
0242     EX_ST_FP(STORE(std, %f18, %o0 + 0x08), memcpy_retl_o2_plus_o4_plus_56)
0243     EX_ST_FP(STORE(std, %f20, %o0 + 0x10), memcpy_retl_o2_plus_o4_plus_48)
0244     EX_ST_FP(STORE(std, %f22, %o0 + 0x18), memcpy_retl_o2_plus_o4_plus_40)
0245     EX_ST_FP(STORE(std, %f24, %o0 + 0x20), memcpy_retl_o2_plus_o4_plus_32)
0246     EX_ST_FP(STORE(std, %f26, %o0 + 0x28), memcpy_retl_o2_plus_o4_plus_24)
0247     EX_ST_FP(STORE(std, %f28, %o0 + 0x30), memcpy_retl_o2_plus_o4_plus_16)
0248     EX_ST_FP(STORE(std, %f30, %o0 + 0x38), memcpy_retl_o2_plus_o4_plus_8)
0249     add     %o0, 0x40, %o0
0250     bne,pt      %icc, 1b
0251      LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
0252 #ifdef NON_USER_COPY
0253     VISExitHalfFast
0254 #else
0255     VISExitHalf
0256 #endif
0257     brz,pn      %o2, .Lexit
0258      cmp        %o2, 19
0259     ble,pn      %icc, .Lsmall_unaligned
0260      nop
0261     ba,a,pt     %icc, .Lmedium_unaligned
0262 
0263 #ifdef NON_USER_COPY
0264 .Lmedium_vis_entry_fail:
0265      or     %o0, %o1, %g2
0266 #endif
0267 .Lmedium:
0268     LOAD(prefetch, %o1 + 0x40, #n_reads_strong)
0269     andcc       %g2, 0x7, %g0
0270     bne,pn      %icc, .Lmedium_unaligned
0271      nop
0272 .Lmedium_noprefetch:
0273     andncc      %o2, 0x20 - 1, %o5
0274     be,pn       %icc, 2f
0275      sub        %o2, %o5, %o2
0276 1:  EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
0277     EX_LD(LOAD(ldx, %o1 + 0x08, %g2), memcpy_retl_o2_plus_o5)
0278     EX_LD(LOAD(ldx, %o1 + 0x10, GLOBAL_SPARE), memcpy_retl_o2_plus_o5)
0279     EX_LD(LOAD(ldx, %o1 + 0x18, %o4), memcpy_retl_o2_plus_o5)
0280     add     %o1, 0x20, %o1
0281     subcc       %o5, 0x20, %o5
0282     EX_ST(STORE(stx, %g1, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_32)
0283     EX_ST(STORE(stx, %g2, %o0 + 0x08), memcpy_retl_o2_plus_o5_plus_24)
0284     EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x10), memcpy_retl_o2_plus_o5_plus_24)
0285     EX_ST(STORE(stx, %o4, %o0 + 0x18), memcpy_retl_o2_plus_o5_plus_8)
0286     bne,pt      %icc, 1b
0287      add        %o0, 0x20, %o0
0288 2:  andcc       %o2, 0x18, %o5
0289     be,pt       %icc, 3f
0290      sub        %o2, %o5, %o2
0291 
0292 1:  EX_LD(LOAD(ldx, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
0293     add     %o1, 0x08, %o1
0294     add     %o0, 0x08, %o0
0295     subcc       %o5, 0x08, %o5
0296     bne,pt      %icc, 1b
0297      EX_ST(STORE(stx, %g1, %o0 - 0x08), memcpy_retl_o2_plus_o5_plus_8)
0298 3:  brz,pt      %o2, .Lexit
0299      cmp        %o2, 0x04
0300     bl,pn       %icc, .Ltiny
0301      nop
0302     EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2)
0303     add     %o1, 0x04, %o1
0304     add     %o0, 0x04, %o0
0305     subcc       %o2, 0x04, %o2
0306     bne,pn      %icc, .Ltiny
0307      EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_4)
0308     ba,a,pt     %icc, .Lexit
0309 .Lmedium_unaligned:
0310     /* First get dest 8 byte aligned.  */
0311     sub     %g0, %o0, %g1
0312     and     %g1, 0x7, %g1
0313     brz,pt      %g1, 2f
0314      sub        %o2, %g1, %o2
0315 
0316 1:  EX_LD(LOAD(ldub, %o1 + 0x00, %g2), memcpy_retl_o2_plus_g1)
0317     add     %o1, 1, %o1
0318     subcc       %g1, 1, %g1
0319     add     %o0, 1, %o0
0320     bne,pt      %icc, 1b
0321      EX_ST(STORE(stb, %g2, %o0 - 0x01), memcpy_retl_o2_plus_g1_plus_1)
0322 2:
0323     and     %o1, 0x7, %g1
0324     brz,pn      %g1, .Lmedium_noprefetch
0325      sll        %g1, 3, %g1
0326     mov     64, %g2
0327     sub     %g2, %g1, %g2
0328     andn        %o1, 0x7, %o1
0329     EX_LD(LOAD(ldx, %o1 + 0x00, %o4), memcpy_retl_o2)
0330     sllx        %o4, %g1, %o4
0331     andn        %o2, 0x08 - 1, %o5
0332     sub     %o2, %o5, %o2
0333 1:  EX_LD(LOAD(ldx, %o1 + 0x08, %g3), memcpy_retl_o2_plus_o5)
0334     add     %o1, 0x08, %o1
0335     subcc       %o5, 0x08, %o5
0336     srlx        %g3, %g2, GLOBAL_SPARE
0337     or      GLOBAL_SPARE, %o4, GLOBAL_SPARE
0338     EX_ST(STORE(stx, GLOBAL_SPARE, %o0 + 0x00), memcpy_retl_o2_plus_o5_plus_8)
0339     add     %o0, 0x08, %o0
0340     bne,pt      %icc, 1b
0341      sllx       %g3, %g1, %o4
0342     srl     %g1, 3, %g1
0343     add     %o1, %g1, %o1
0344     brz,pn      %o2, .Lexit
0345      nop
0346     ba,pt       %icc, .Lsmall_unaligned
0347 
0348 .Ltiny:
0349     EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
0350     subcc       %o2, 1, %o2
0351     be,pn       %icc, .Lexit
0352      EX_ST(STORE(stb, %g1, %o0 + 0x00), memcpy_retl_o2_plus_1)
0353     EX_LD(LOAD(ldub, %o1 + 0x01, %g1), memcpy_retl_o2)
0354     subcc       %o2, 1, %o2
0355     be,pn       %icc, .Lexit
0356      EX_ST(STORE(stb, %g1, %o0 + 0x01), memcpy_retl_o2_plus_1)
0357     EX_LD(LOAD(ldub, %o1 + 0x02, %g1), memcpy_retl_o2)
0358     ba,pt       %icc, .Lexit
0359      EX_ST(STORE(stb, %g1, %o0 + 0x02), memcpy_retl_o2)
0360 
0361 .Lsmall:
0362     andcc       %g2, 0x3, %g0
0363     bne,pn      %icc, .Lsmall_unaligned
0364      andn       %o2, 0x4 - 1, %o5
0365     sub     %o2, %o5, %o2
0366 1:
0367     EX_LD(LOAD(lduw, %o1 + 0x00, %g1), memcpy_retl_o2_plus_o5)
0368     add     %o1, 0x04, %o1
0369     subcc       %o5, 0x04, %o5
0370     add     %o0, 0x04, %o0
0371     bne,pt      %icc, 1b
0372      EX_ST(STORE(stw, %g1, %o0 - 0x04), memcpy_retl_o2_plus_o5_plus_4)
0373     brz,pt      %o2, .Lexit
0374      nop
0375     ba,a,pt     %icc, .Ltiny
0376 
0377 .Lsmall_unaligned:
0378 1:  EX_LD(LOAD(ldub, %o1 + 0x00, %g1), memcpy_retl_o2)
0379     add     %o1, 1, %o1
0380     add     %o0, 1, %o0
0381     subcc       %o2, 1, %o2
0382     bne,pt      %icc, 1b
0383      EX_ST(STORE(stb, %g1, %o0 - 0x01), memcpy_retl_o2_plus_1)
0384     ba,a,pt     %icc, .Lexit
0385      nop
0386     .size       FUNC_NAME, .-FUNC_NAME