aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-08-08 20:11:39 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-08-08 20:33:45 -0400
commit6c70b6fc7b6fc321636a014082d9e32333da1f80 (patch)
treeff0e52bb7ba43b058b7cbb88b952fd268fbe3ad2 /arch/sparc64
parent68c9f9fd336dc7e793cecad25f8ac40ccaa7a256 (diff)
[SPARC64]: Do not assume sun4v chips have load-twin/store-init support.
Check the cpu type in the OBP device tree before committing to using the optimized Niagara memcpy and memset implementation. If we don't recognize the cpu type, use a completely generic version. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/kernel/cpu.c42
-rw-r--r--arch/sparc64/kernel/head.S111
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c1
-rw-r--r--arch/sparc64/lib/GENbzero.S160
-rw-r--r--arch/sparc64/lib/GENcopy_from_user.S34
-rw-r--r--arch/sparc64/lib/GENcopy_to_user.S38
-rw-r--r--arch/sparc64/lib/GENmemcpy.S121
-rw-r--r--arch/sparc64/lib/GENpage.S77
-rw-r--r--arch/sparc64/lib/GENpatch.S33
-rw-r--r--arch/sparc64/lib/Makefile4
10 files changed, 588 insertions, 33 deletions
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index e4eff878123d..e43db73f2b91 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -13,7 +13,7 @@
13#include <asm/fpumacro.h> 13#include <asm/fpumacro.h>
14#include <asm/cpudata.h> 14#include <asm/cpudata.h>
15#include <asm/spitfire.h> 15#include <asm/spitfire.h>
16#include <asm/prom.h> 16#include <asm/oplib.h>
17 17
18DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; 18DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
19 19
@@ -69,36 +69,24 @@ unsigned int fsr_storage;
69 69
70static void __init sun4v_cpu_probe(void) 70static void __init sun4v_cpu_probe(void)
71{ 71{
72 struct device_node *dp; 72 switch (sun4v_chip_type) {
73 const char *compat; 73 case SUN4V_CHIP_NIAGARA1:
74 int len;
75
76 dp = of_find_node_by_name(NULL, "cpu");
77 if (!dp)
78 goto no_compat;
79
80 compat = of_get_property(dp, "compatible", &len);
81 if (!compat)
82 goto no_compat;
83
84 if (of_find_in_proplist(compat, "SUNW,UltraSPARC-T1", len)) {
85 sparc_cpu_type = "UltraSparc T1 (Niagara)"; 74 sparc_cpu_type = "UltraSparc T1 (Niagara)";
86 sparc_fpu_type = "UltraSparc T1 integrated FPU"; 75 sparc_fpu_type = "UltraSparc T1 integrated FPU";
87 } else if (of_find_in_proplist(compat, "SUNW,UltraSPARC-T2", len)) { 76 break;
77
78 case SUN4V_CHIP_NIAGARA2:
88 sparc_cpu_type = "UltraSparc T2 (Niagara2)"; 79 sparc_cpu_type = "UltraSparc T2 (Niagara2)";
89 sparc_fpu_type = "UltraSparc T2 integrated FPU"; 80 sparc_fpu_type = "UltraSparc T2 integrated FPU";
90 } else 81 break;
91 goto unknown; 82
92 83 default:
93 return; 84 printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
94 85 prom_cpu_compatible);
95no_compat: 86 sparc_cpu_type = "Unknown SUN4V CPU";
96 compat = "no property"; 87 sparc_fpu_type = "Unknown SUN4V FPU";
97 88 break;
98unknown: 89 }
99 printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n", compat);
100 sparc_cpu_type = "Unknown SUN4V CPU";
101 sparc_fpu_type = "Unknown SUN4V FPU";
102} 90}
103 91
104void __init cpu_probe(void) 92void __init cpu_probe(void)
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 9dbd833d79d6..ac18bd8e273f 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -97,7 +97,8 @@ sparc64_boot:
97 .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache 97 .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
98 .globl prom_boot_mapped_pc, prom_boot_mapping_mode 98 .globl prom_boot_mapped_pc, prom_boot_mapping_mode
99 .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low 99 .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
100 .globl is_sun4v 100 .globl prom_compatible_name, prom_cpu_path, prom_cpu_compatible
101 .globl is_sun4v, sun4v_chip_type
101prom_peer_name: 102prom_peer_name:
102 .asciz "peer" 103 .asciz "peer"
103prom_compatible_name: 104prom_compatible_name:
@@ -106,6 +107,8 @@ prom_finddev_name:
106 .asciz "finddevice" 107 .asciz "finddevice"
107prom_chosen_path: 108prom_chosen_path:
108 .asciz "/chosen" 109 .asciz "/chosen"
110prom_cpu_path:
111 .asciz "/cpu"
109prom_getprop_name: 112prom_getprop_name:
110 .asciz "getprop" 113 .asciz "getprop"
111prom_mmu_name: 114prom_mmu_name:
@@ -120,9 +123,13 @@ prom_unmap_name:
120 .asciz "unmap" 123 .asciz "unmap"
121prom_sun4v_name: 124prom_sun4v_name:
122 .asciz "sun4v" 125 .asciz "sun4v"
126prom_niagara_prefix:
127 .asciz "SUNW,UltraSPARC-T"
123 .align 4 128 .align 4
124prom_root_compatible: 129prom_root_compatible:
125 .skip 64 130 .skip 64
131prom_cpu_compatible:
132 .skip 64
126prom_root_node: 133prom_root_node:
127 .word 0 134 .word 0
128prom_mmu_ihandle_cache: 135prom_mmu_ihandle_cache:
@@ -138,6 +145,8 @@ prom_boot_mapping_phys_low:
138 .xword 0 145 .xword 0
139is_sun4v: 146is_sun4v:
140 .word 0 147 .word 0
148sun4v_chip_type:
149 .word SUN4V_CHIP_INVALID
1411: 1501:
142 rd %pc, %l0 151 rd %pc, %l0
143 152
@@ -296,13 +305,13 @@ is_sun4v:
296 sethi %hi(prom_sun4v_name), %g7 305 sethi %hi(prom_sun4v_name), %g7
297 or %g7, %lo(prom_sun4v_name), %g7 306 or %g7, %lo(prom_sun4v_name), %g7
298 mov 5, %g3 307 mov 5, %g3
2991: ldub [%g7], %g2 30890: ldub [%g7], %g2
300 ldub [%g1], %g4 309 ldub [%g1], %g4
301 cmp %g2, %g4 310 cmp %g2, %g4
302 bne,pn %icc, 2f 311 bne,pn %icc, 80f
303 add %g7, 1, %g7 312 add %g7, 1, %g7
304 subcc %g3, 1, %g3 313 subcc %g3, 1, %g3
305 bne,pt %xcc, 1b 314 bne,pt %xcc, 90b
306 add %g1, 1, %g1 315 add %g1, 1, %g1
307 316
308 sethi %hi(is_sun4v), %g1 317 sethi %hi(is_sun4v), %g1
@@ -310,7 +319,80 @@ is_sun4v:
310 mov 1, %g7 319 mov 1, %g7
311 stw %g7, [%g1] 320 stw %g7, [%g1]
312 321
3132: 322 /* cpu_node = prom_finddevice("/cpu") */
323 mov (1b - prom_finddev_name), %l1
324 mov (1b - prom_cpu_path), %l2
325 sub %l0, %l1, %l1
326 sub %l0, %l2, %l2
327 sub %sp, (192 + 128), %sp
328
329 stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "finddevice"
330 mov 1, %l3
331 stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
332 stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
333 stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, "/cpu"
334 stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
335 call %l7
336 add %sp, (2047 + 128), %o0 ! argument array
337
338 ldx [%sp + 2047 + 128 + 0x20], %l4 ! cpu device node
339
340 mov (1b - prom_getprop_name), %l1
341 mov (1b - prom_compatible_name), %l2
342 mov (1b - prom_cpu_compatible), %l5
343 sub %l0, %l1, %l1
344 sub %l0, %l2, %l2
345 sub %l0, %l5, %l5
346
347 /* prom_getproperty(cpu_node, "compatible",
348 * &prom_cpu_compatible, 64)
349 */
350 stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
351 mov 4, %l3
352 stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
353 mov 1, %l3
354 stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
355 stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, cpu_node
356 stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible"
357 stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_cpu_compatible
358 mov 64, %l3
359 stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size
360 stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
361 call %l7
362 add %sp, (2047 + 128), %o0 ! argument array
363
364 add %sp, (192 + 128), %sp
365
366 sethi %hi(prom_cpu_compatible), %g1
367 or %g1, %lo(prom_cpu_compatible), %g1
368 sethi %hi(prom_niagara_prefix), %g7
369 or %g7, %lo(prom_niagara_prefix), %g7
370 mov 17, %g3
37190: ldub [%g7], %g2
372 ldub [%g1], %g4
373 cmp %g2, %g4
374 bne,pn %icc, 4f
375 add %g7, 1, %g7
376 subcc %g3, 1, %g3
377 bne,pt %xcc, 90b
378 add %g1, 1, %g1
379
380 sethi %hi(prom_cpu_compatible), %g1
381 or %g1, %lo(prom_cpu_compatible), %g1
382 ldub [%g1 + 17], %g2
383 cmp %g2, '1'
384 be,pt %xcc, 5f
385 mov SUN4V_CHIP_NIAGARA1, %g4
386 cmp %g2, '2'
387 be,pt %xcc, 5f
388 mov SUN4V_CHIP_NIAGARA2, %g4
3894:
390 mov SUN4V_CHIP_UNKNOWN, %g4
3915: sethi %hi(sun4v_chip_type), %g2
392 or %g2, %lo(sun4v_chip_type), %g2
393 stw %g4, [%g2]
394
39580:
314 BRANCH_IF_SUN4V(g1, jump_to_sun4u_init) 396 BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
315 BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot) 397 BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
316 BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot) 398 BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
@@ -414,6 +496,24 @@ niagara_tlb_fixup:
414 stw %g2, [%g1 + %lo(tlb_type)] 496 stw %g2, [%g1 + %lo(tlb_type)]
415 497
416 /* Patch copy/clear ops. */ 498 /* Patch copy/clear ops. */
499 sethi %hi(sun4v_chip_type), %g1
500 lduw [%g1 + %lo(sun4v_chip_type)], %g1
501 cmp %g1, SUN4V_CHIP_NIAGARA1
502 be,pt %xcc, niagara_patch
503 cmp %g1, SUN4V_CHIP_NIAGARA2
504 be,pt %xcc, niagara_patch
505 nop
506
507 call generic_patch_copyops
508 nop
509 call generic_patch_bzero
510 nop
511 call generic_patch_pageops
512 nop
513
514 ba,a,pt %xcc, 80f
515
516niagara_patch:
417 call niagara_patch_copyops 517 call niagara_patch_copyops
418 nop 518 nop
419 call niagara_patch_bzero 519 call niagara_patch_bzero
@@ -421,6 +521,7 @@ niagara_tlb_fixup:
421 call niagara_patch_pageops 521 call niagara_patch_pageops
422 nop 522 nop
423 523
52480:
424 /* Patch TLB/cache ops. */ 525 /* Patch TLB/cache ops. */
425 call hypervisor_patch_cachetlbops 526 call hypervisor_patch_cachetlbops
426 nop 527 nop
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index d270c2f0be0f..23fad7ebdd0d 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -168,6 +168,7 @@ EXPORT_SYMBOL(change_bit);
168EXPORT_SYMBOL(__flushw_user); 168EXPORT_SYMBOL(__flushw_user);
169 169
170EXPORT_SYMBOL(tlb_type); 170EXPORT_SYMBOL(tlb_type);
171EXPORT_SYMBOL(sun4v_chip_type);
171EXPORT_SYMBOL(get_fb_unmapped_area); 172EXPORT_SYMBOL(get_fb_unmapped_area);
172EXPORT_SYMBOL(flush_icache_range); 173EXPORT_SYMBOL(flush_icache_range);
173 174
diff --git a/arch/sparc64/lib/GENbzero.S b/arch/sparc64/lib/GENbzero.S
new file mode 100644
index 000000000000..f9c71d64eba1
--- /dev/null
+++ b/arch/sparc64/lib/GENbzero.S
@@ -0,0 +1,160 @@
1/* GENbzero.S: Generic sparc64 memset/clear_user.
2 *
3 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
4 */
5#include <asm/asi.h>
6
7#define EX_ST(x,y) \
898: x,y; \
9 .section .fixup; \
10 .align 4; \
1199: retl; \
12 mov %o1, %o0; \
13 .section __ex_table; \
14 .align 4; \
15 .word 98b, 99b; \
16 .text; \
17 .align 4;
18
19 .align 32
20 .text
21
22 .globl GENmemset
23 .type GENmemset, #function
24GENmemset: /* %o0=buf, %o1=pat, %o2=len */
25 and %o1, 0xff, %o3
26 mov %o2, %o1
27 sllx %o3, 8, %g1
28 or %g1, %o3, %o2
29 sllx %o2, 16, %g1
30 or %g1, %o2, %o2
31 sllx %o2, 32, %g1
32 ba,pt %xcc, 1f
33 or %g1, %o2, %o2
34
35 .globl GENbzero
36 .type GENbzero, #function
37GENbzero:
38 clr %o2
391: brz,pn %o1, GENbzero_return
40 mov %o0, %o3
41
42 /* %o5: saved %asi, restored at GENbzero_done
43 * %o4: store %asi to use
44 */
45 rd %asi, %o5
46 mov ASI_P, %o4
47 wr %o4, 0x0, %asi
48
49GENbzero_from_clear_user:
50 cmp %o1, 15
51 bl,pn %icc, GENbzero_tiny
52 andcc %o0, 0x7, %g1
53 be,pt %xcc, 2f
54 mov 8, %g2
55 sub %g2, %g1, %g1
56 sub %o1, %g1, %o1
571: EX_ST(stba %o2, [%o0 + 0x00] %asi)
58 subcc %g1, 1, %g1
59 bne,pt %xcc, 1b
60 add %o0, 1, %o0
612: cmp %o1, 128
62 bl,pn %icc, GENbzero_medium
63 andcc %o0, (64 - 1), %g1
64 be,pt %xcc, GENbzero_pre_loop
65 mov 64, %g2
66 sub %g2, %g1, %g1
67 sub %o1, %g1, %o1
681: EX_ST(stxa %o2, [%o0 + 0x00] %asi)
69 subcc %g1, 8, %g1
70 bne,pt %xcc, 1b
71 add %o0, 8, %o0
72
73GENbzero_pre_loop:
74 andn %o1, (64 - 1), %g1
75 sub %o1, %g1, %o1
76GENbzero_loop:
77 EX_ST(stxa %o2, [%o0 + 0x00] %asi)
78 EX_ST(stxa %o2, [%o0 + 0x08] %asi)
79 EX_ST(stxa %o2, [%o0 + 0x10] %asi)
80 EX_ST(stxa %o2, [%o0 + 0x18] %asi)
81 EX_ST(stxa %o2, [%o0 + 0x20] %asi)
82 EX_ST(stxa %o2, [%o0 + 0x28] %asi)
83 EX_ST(stxa %o2, [%o0 + 0x30] %asi)
84 EX_ST(stxa %o2, [%o0 + 0x38] %asi)
85 subcc %g1, 64, %g1
86 bne,pt %xcc, GENbzero_loop
87 add %o0, 64, %o0
88
89 membar #Sync
90 wr %o4, 0x0, %asi
91 brz,pn %o1, GENbzero_done
92GENbzero_medium:
93 andncc %o1, 0x7, %g1
94 be,pn %xcc, 2f
95 sub %o1, %g1, %o1
961: EX_ST(stxa %o2, [%o0 + 0x00] %asi)
97 subcc %g1, 8, %g1
98 bne,pt %xcc, 1b
99 add %o0, 8, %o0
1002: brz,pt %o1, GENbzero_done
101 nop
102
103GENbzero_tiny:
1041: EX_ST(stba %o2, [%o0 + 0x00] %asi)
105 subcc %o1, 1, %o1
106 bne,pt %icc, 1b
107 add %o0, 1, %o0
108
109 /* fallthrough */
110
111GENbzero_done:
112 wr %o5, 0x0, %asi
113
114GENbzero_return:
115 retl
116 mov %o3, %o0
117 .size GENbzero, .-GENbzero
118 .size GENmemset, .-GENmemset
119
120 .globl GENclear_user
121 .type GENclear_user, #function
122GENclear_user: /* %o0=buf, %o1=len */
123 rd %asi, %o5
124 brz,pn %o1, GENbzero_done
125 clr %o3
126 cmp %o5, ASI_AIUS
127 bne,pn %icc, GENbzero
128 clr %o2
129 ba,pt %xcc, GENbzero_from_clear_user
130 mov ASI_AIUS, %o4
131 .size GENclear_user, .-GENclear_user
132
133#define BRANCH_ALWAYS 0x10680000
134#define NOP 0x01000000
135#define GEN_DO_PATCH(OLD, NEW) \
136 sethi %hi(NEW), %g1; \
137 or %g1, %lo(NEW), %g1; \
138 sethi %hi(OLD), %g2; \
139 or %g2, %lo(OLD), %g2; \
140 sub %g1, %g2, %g1; \
141 sethi %hi(BRANCH_ALWAYS), %g3; \
142 sll %g1, 11, %g1; \
143 srl %g1, 11 + 2, %g1; \
144 or %g3, %lo(BRANCH_ALWAYS), %g3; \
145 or %g3, %g1, %g3; \
146 stw %g3, [%g2]; \
147 sethi %hi(NOP), %g3; \
148 or %g3, %lo(NOP), %g3; \
149 stw %g3, [%g2 + 0x4]; \
150 flush %g2;
151
152 .globl generic_patch_bzero
153 .type generic_patch_bzero,#function
154generic_patch_bzero:
155 GEN_DO_PATCH(memset, GENmemset)
156 GEN_DO_PATCH(__bzero, GENbzero)
157 GEN_DO_PATCH(__clear_user, GENclear_user)
158 retl
159 nop
160 .size generic_patch_bzero,.-generic_patch_bzero
diff --git a/arch/sparc64/lib/GENcopy_from_user.S b/arch/sparc64/lib/GENcopy_from_user.S
new file mode 100644
index 000000000000..2b9df99e87f9
--- /dev/null
+++ b/arch/sparc64/lib/GENcopy_from_user.S
@@ -0,0 +1,34 @@
1/* GENcopy_from_user.S: Generic sparc64 copy from userspace.
2 *
3 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
4 */
5
6#define EX_LD(x) \
798: x; \
8 .section .fixup; \
9 .align 4; \
1099: retl; \
11 mov 1, %o0; \
12 .section __ex_table,"a";\
13 .align 4; \
14 .word 98b, 99b; \
15 .text; \
16 .align 4;
17
18#ifndef ASI_AIUS
19#define ASI_AIUS 0x11
20#endif
21
22#define FUNC_NAME GENcopy_from_user
23#define LOAD(type,addr,dest) type##a [addr] ASI_AIUS, dest
24#define EX_RETVAL(x) 0
25
26#ifdef __KERNEL__
27#define PREAMBLE \
28 rd %asi, %g1; \
29 cmp %g1, ASI_AIUS; \
30 bne,pn %icc, memcpy_user_stub; \
31 nop
32#endif
33
34#include "GENmemcpy.S"
diff --git a/arch/sparc64/lib/GENcopy_to_user.S b/arch/sparc64/lib/GENcopy_to_user.S
new file mode 100644
index 000000000000..bb3f7084daf9
--- /dev/null
+++ b/arch/sparc64/lib/GENcopy_to_user.S
@@ -0,0 +1,38 @@
1/* GENcopy_to_user.S: Generic sparc64 copy to userspace.
2 *
3 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
4 */
5
6#define EX_ST(x) \
798: x; \
8 .section .fixup; \
9 .align 4; \
1099: retl; \
11 mov 1, %o0; \
12 .section __ex_table,"a";\
13 .align 4; \
14 .word 98b, 99b; \
15 .text; \
16 .align 4;
17
18#ifndef ASI_AIUS
19#define ASI_AIUS 0x11
20#endif
21
22#define FUNC_NAME GENcopy_to_user
23#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS
24#define EX_RETVAL(x) 0
25
26#ifdef __KERNEL__
27 /* Writing to %asi is _expensive_ so we hardcode it.
28 * Reading %asi to check for KERNEL_DS is comparatively
29 * cheap.
30 */
31#define PREAMBLE \
32 rd %asi, %g1; \
33 cmp %g1, ASI_AIUS; \
34 bne,pn %icc, memcpy_user_stub; \
35 nop
36#endif
37
38#include "GENmemcpy.S"
diff --git a/arch/sparc64/lib/GENmemcpy.S b/arch/sparc64/lib/GENmemcpy.S
new file mode 100644
index 000000000000..89358ee94851
--- /dev/null
+++ b/arch/sparc64/lib/GENmemcpy.S
@@ -0,0 +1,121 @@
1/* GENmemcpy.S: Generic sparc64 memcpy.
2 *
3 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
4 */
5
6#ifdef __KERNEL__
7#define GLOBAL_SPARE %g7
8#else
9#define GLOBAL_SPARE %g5
10#endif
11
12#ifndef EX_LD
13#define EX_LD(x) x
14#endif
15
16#ifndef EX_ST
17#define EX_ST(x) x
18#endif
19
20#ifndef EX_RETVAL
21#define EX_RETVAL(x) x
22#endif
23
24#ifndef LOAD
25#define LOAD(type,addr,dest) type [addr], dest
26#endif
27
28#ifndef STORE
29#define STORE(type,src,addr) type src, [addr]
30#endif
31
32#ifndef FUNC_NAME
33#define FUNC_NAME GENmemcpy
34#endif
35
36#ifndef PREAMBLE
37#define PREAMBLE
38#endif
39
40#ifndef XCC
41#define XCC xcc
42#endif
43
44 .register %g2,#scratch
45 .register %g3,#scratch
46
47 .text
48 .align 64
49
50 .globl FUNC_NAME
51 .type FUNC_NAME,#function
52FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
53 srlx %o2, 31, %g2
54 cmp %g2, 0
55 tne %XCC, 5
56 PREAMBLE
57 mov %o0, GLOBAL_SPARE
58
59 cmp %o2, 0
60 be,pn %XCC, 85f
61 or %o0, %o1, %o3
62 cmp %o2, 16
63 blu,a,pn %XCC, 80f
64 or %o3, %o2, %o3
65
66 xor %o0, %o1, %o4
67 andcc %o4, 0x7, %g0
68 bne,a,pn %XCC, 90f
69 sub %o0, %o1, %o3
70
71 and %o0, 0x7, %o4
72 sub %o4, 0x8, %o4
73 sub %g0, %o4, %o4
74 sub %o2, %o4, %o2
751: subcc %o4, 1, %o4
76 EX_LD(LOAD(ldub, %o1, %g1))
77 EX_ST(STORE(stb, %g1, %o0))
78 add %o1, 1, %o1
79 bne,pt %XCC, 1b
80 add %o0, 1, %o0
81
82 andn %o2, 0x7, %g1
83 sub %o2, %g1, %o2
841: subcc %g1, 0x8, %g1
85 EX_LD(LOAD(ldx, %o1, %g2))
86 EX_ST(STORE(stx, %g2, %o0))
87 add %o1, 0x8, %o1
88 bne,pt %XCC, 1b
89 add %o0, 0x8, %o0
90
91 brz,pt %o2, 85f
92 sub %o0, %o1, %o3
93 ba,a,pt %XCC, 90f
94
95 .align 64
9680: /* 0 < len <= 16 */
97 andcc %o3, 0x3, %g0
98 bne,pn %XCC, 90f
99 sub %o0, %o1, %o3
100
1011:
102 subcc %o2, 4, %o2
103 EX_LD(LOAD(lduw, %o1, %g1))
104 EX_ST(STORE(stw, %g1, %o1 + %o3))
105 bgu,pt %XCC, 1b
106 add %o1, 4, %o1
107
10885: retl
109 mov EX_RETVAL(GLOBAL_SPARE), %o0
110
111 .align 32
11290:
113 subcc %o2, 1, %o2
114 EX_LD(LOAD(ldub, %o1, %g1))
115 EX_ST(STORE(stb, %g1, %o1 + %o3))
116 bgu,pt %XCC, 90b
117 add %o1, 1, %o1
118 retl
119 mov EX_RETVAL(GLOBAL_SPARE), %o0
120
121 .size FUNC_NAME, .-FUNC_NAME
diff --git a/arch/sparc64/lib/GENpage.S b/arch/sparc64/lib/GENpage.S
new file mode 100644
index 000000000000..2ef9d05f21bc
--- /dev/null
+++ b/arch/sparc64/lib/GENpage.S
@@ -0,0 +1,77 @@
1/* GENpage.S: Generic clear and copy page.
2 *
3 * Copyright (C) 2007 (davem@davemloft.net)
4 */
5#include <asm/page.h>
6
7 .text
8 .align 32
9
10GENcopy_user_page:
11 set PAGE_SIZE, %g7
121: ldx [%o1 + 0x00], %o2
13 ldx [%o1 + 0x08], %o3
14 ldx [%o1 + 0x10], %o4
15 ldx [%o1 + 0x18], %o5
16 stx %o2, [%o0 + 0x00]
17 stx %o3, [%o0 + 0x08]
18 stx %o4, [%o0 + 0x10]
19 stx %o5, [%o0 + 0x18]
20 ldx [%o1 + 0x20], %o2
21 ldx [%o1 + 0x28], %o3
22 ldx [%o1 + 0x30], %o4
23 ldx [%o1 + 0x38], %o5
24 stx %o2, [%o0 + 0x20]
25 stx %o3, [%o0 + 0x28]
26 stx %o4, [%o0 + 0x30]
27 stx %o5, [%o0 + 0x38]
28 subcc %g7, 64, %g7
29 add %o1, 64, %o1
30 bne,pt %xcc, 1b
31 add %o0, 64, %o0
32 retl
33 nop
34
35GENclear_page:
36GENclear_user_page:
37 set PAGE_SIZE, %g7
381: stx %g0, [%o0 + 0x00]
39 stx %g0, [%o0 + 0x08]
40 stx %g0, [%o0 + 0x10]
41 stx %g0, [%o0 + 0x18]
42 stx %g0, [%o0 + 0x20]
43 stx %g0, [%o0 + 0x28]
44 stx %g0, [%o0 + 0x30]
45 stx %g0, [%o0 + 0x38]
46 subcc %g7, 64, %g7
47 bne,pt %xcc, 1b
48 add %o0, 64, %o0
49
50#define BRANCH_ALWAYS 0x10680000
51#define NOP 0x01000000
52#define GEN_DO_PATCH(OLD, NEW) \
53 sethi %hi(NEW), %g1; \
54 or %g1, %lo(NEW), %g1; \
55 sethi %hi(OLD), %g2; \
56 or %g2, %lo(OLD), %g2; \
57 sub %g1, %g2, %g1; \
58 sethi %hi(BRANCH_ALWAYS), %g3; \
59 sll %g1, 11, %g1; \
60 srl %g1, 11 + 2, %g1; \
61 or %g3, %lo(BRANCH_ALWAYS), %g3; \
62 or %g3, %g1, %g3; \
63 stw %g3, [%g2]; \
64 sethi %hi(NOP), %g3; \
65 or %g3, %lo(NOP), %g3; \
66 stw %g3, [%g2 + 0x4]; \
67 flush %g2;
68
69 .globl generic_patch_pageops
70 .type generic_patch_pageops,#function
71generic_patch_pageops:
72 GEN_DO_PATCH(copy_user_page, GENcopy_user_page)
73 GEN_DO_PATCH(_clear_page, GENclear_page)
74 GEN_DO_PATCH(clear_user_page, GENclear_user_page)
75 retl
76 nop
77 .size generic_patch_pageops,.-generic_patch_pageops
diff --git a/arch/sparc64/lib/GENpatch.S b/arch/sparc64/lib/GENpatch.S
new file mode 100644
index 000000000000..fab9e89f16bd
--- /dev/null
+++ b/arch/sparc64/lib/GENpatch.S
@@ -0,0 +1,33 @@
1/* GENpatch.S: Patch Ultra-I routines with generic variant.
2 *
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
4 */
5
6#define BRANCH_ALWAYS 0x10680000
7#define NOP 0x01000000
8#define GEN_DO_PATCH(OLD, NEW) \
9 sethi %hi(NEW), %g1; \
10 or %g1, %lo(NEW), %g1; \
11 sethi %hi(OLD), %g2; \
12 or %g2, %lo(OLD), %g2; \
13 sub %g1, %g2, %g1; \
14 sethi %hi(BRANCH_ALWAYS), %g3; \
15 sll %g1, 11, %g1; \
16 srl %g1, 11 + 2, %g1; \
17 or %g3, %lo(BRANCH_ALWAYS), %g3; \
18 or %g3, %g1, %g3; \
19 stw %g3, [%g2]; \
20 sethi %hi(NOP), %g3; \
21 or %g3, %lo(NOP), %g3; \
22 stw %g3, [%g2 + 0x4]; \
23 flush %g2;
24
25 .globl generic_patch_copyops
26 .type generic_patch_copyops,#function
27generic_patch_copyops:
28 GEN_DO_PATCH(memcpy, GENmemcpy)
29 GEN_DO_PATCH(___copy_from_user, GENcopy_from_user)
30 GEN_DO_PATCH(___copy_to_user, GENcopy_to_user)
31 retl
32 nop
33 .size generic_patch_copyops,.-generic_patch_copyops
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index c4a6d6e7d03c..f95fbfa3eeb8 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -1,4 +1,4 @@
1# $Id: Makefile,v 1.25 2000/12/14 22:57:25 davem Exp $ 1#
2# Makefile for Sparc64 library files.. 2# Makefile for Sparc64 library files..
3# 3#
4 4
@@ -13,6 +13,8 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
13 U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \ 13 U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
14 NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \ 14 NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
15 NGpage.o NGbzero.o \ 15 NGpage.o NGbzero.o \
16 GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o GENpatch.o \
17 GENpage.o GENbzero.o \
16 copy_in_user.o user_fixup.o memmove.o \ 18 copy_in_user.o user_fixup.o memmove.o \
17 mcount.o ipcsum.o rwsem.o xor.o 19 mcount.o ipcsum.o rwsem.o xor.o
18 20