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 102FUNC_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 1291: 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 13651: 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 1591: 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 1711: 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) 2221: 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 2751: 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 2872: andcc %o2, 0x18, %o5 288 be,pt %icc, 3f 289 sub %o2, %o5, %o2 290 2911: 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) 2973: 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 3151: 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) 3212: 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 3321: 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 3651: 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: 3771: 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 386