diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-08-09 11:27:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-08-09 11:27:25 -0400 |
commit | e7bc15a9ad07269c48732e9a9874e5938b4700ee (patch) | |
tree | dfe010e71720a534a15bb38cd454c7f80db2b1f3 /arch | |
parent | 5a0276b7ae1fcd90cea07f65452aebbd1b0743c5 (diff) | |
parent | b434e71933aa0519ee042c01419db76b7dcc058e (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
[SPARC64]: Fix memory leak when cpu hotplugging.
[SPARC64]: Do not assume sun4v chips have load-twin/store-init support.
[SPARC64]: Fix hard-coding of cpu type output in /proc/cpuinfo on sun4v.
[SPARC]: Centralize find_in_proplist() instead of duplicating N times.
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/kernel/prom.c | 15 | ||||
-rw-r--r-- | arch/sparc64/kernel/cpu.c | 36 | ||||
-rw-r--r-- | arch/sparc64/kernel/head.S | 111 | ||||
-rw-r--r-- | arch/sparc64/kernel/hvtramp.S | 7 | ||||
-rw-r--r-- | arch/sparc64/kernel/irq.c | 74 | ||||
-rw-r--r-- | arch/sparc64/kernel/mdesc.c | 24 | ||||
-rw-r--r-- | arch/sparc64/kernel/prom.c | 15 | ||||
-rw-r--r-- | arch/sparc64/kernel/smp.c | 5 | ||||
-rw-r--r-- | arch/sparc64/kernel/sparc64_ksyms.c | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/trampoline.S | 7 | ||||
-rw-r--r-- | arch/sparc64/kernel/vio.c | 19 | ||||
-rw-r--r-- | arch/sparc64/lib/GENbzero.S | 160 | ||||
-rw-r--r-- | arch/sparc64/lib/GENcopy_from_user.S | 34 | ||||
-rw-r--r-- | arch/sparc64/lib/GENcopy_to_user.S | 38 | ||||
-rw-r--r-- | arch/sparc64/lib/GENmemcpy.S | 121 | ||||
-rw-r--r-- | arch/sparc64/lib/GENpage.S | 77 | ||||
-rw-r--r-- | arch/sparc64/lib/GENpatch.S | 33 | ||||
-rw-r--r-- | arch/sparc64/lib/Makefile | 4 |
18 files changed, 666 insertions, 115 deletions
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 39fbd3c8ab0b..cd4fb79aa3a8 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c | |||
@@ -102,6 +102,21 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len | |||
102 | } | 102 | } |
103 | EXPORT_SYMBOL(of_set_property); | 103 | EXPORT_SYMBOL(of_set_property); |
104 | 104 | ||
105 | int of_find_in_proplist(const char *list, const char *match, int len) | ||
106 | { | ||
107 | while (len > 0) { | ||
108 | int l; | ||
109 | |||
110 | if (!strcmp(list, match)) | ||
111 | return 1; | ||
112 | l = strlen(list) + 1; | ||
113 | list += l; | ||
114 | len -= l; | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | EXPORT_SYMBOL(of_find_in_proplist); | ||
119 | |||
105 | static unsigned int prom_early_allocated; | 120 | static unsigned int prom_early_allocated; |
106 | 121 | ||
107 | static void * __init prom_early_alloc(unsigned long size) | 122 | static void * __init prom_early_alloc(unsigned long size) |
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c index 7eb81d3954d9..e43db73f2b91 100644 --- a/arch/sparc64/kernel/cpu.c +++ b/arch/sparc64/kernel/cpu.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* cpu.c: Dinky routines to look for the kind of Sparc cpu | 1 | /* cpu.c: Dinky routines to look for the kind of Sparc cpu |
2 | * we are on. | 2 | * we are on. |
3 | * | 3 | * |
4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | 4 | * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
@@ -13,6 +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/oplib.h> | ||
16 | 17 | ||
17 | DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; | 18 | DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; |
18 | 19 | ||
@@ -61,21 +62,40 @@ struct cpu_iu_info linux_sparc_chips[] = { | |||
61 | 62 | ||
62 | #define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips) | 63 | #define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips) |
63 | 64 | ||
64 | char *sparc_cpu_type = "cpu-oops"; | 65 | char *sparc_cpu_type; |
65 | char *sparc_fpu_type = "fpu-oops"; | 66 | char *sparc_fpu_type; |
66 | 67 | ||
67 | unsigned int fsr_storage; | 68 | unsigned int fsr_storage; |
68 | 69 | ||
70 | static void __init sun4v_cpu_probe(void) | ||
71 | { | ||
72 | switch (sun4v_chip_type) { | ||
73 | case SUN4V_CHIP_NIAGARA1: | ||
74 | sparc_cpu_type = "UltraSparc T1 (Niagara)"; | ||
75 | sparc_fpu_type = "UltraSparc T1 integrated FPU"; | ||
76 | break; | ||
77 | |||
78 | case SUN4V_CHIP_NIAGARA2: | ||
79 | sparc_cpu_type = "UltraSparc T2 (Niagara2)"; | ||
80 | sparc_fpu_type = "UltraSparc T2 integrated FPU"; | ||
81 | break; | ||
82 | |||
83 | default: | ||
84 | printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n", | ||
85 | prom_cpu_compatible); | ||
86 | sparc_cpu_type = "Unknown SUN4V CPU"; | ||
87 | sparc_fpu_type = "Unknown SUN4V FPU"; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | |||
69 | void __init cpu_probe(void) | 92 | void __init cpu_probe(void) |
70 | { | 93 | { |
71 | unsigned long ver, fpu_vers, manuf, impl, fprs; | 94 | unsigned long ver, fpu_vers, manuf, impl, fprs; |
72 | int i; | 95 | int i; |
73 | 96 | ||
74 | if (tlb_type == hypervisor) { | 97 | if (tlb_type == hypervisor) |
75 | sparc_cpu_type = "UltraSparc T1 (Niagara)"; | 98 | return sun4v_cpu_probe(); |
76 | sparc_fpu_type = "UltraSparc T1 integrated FPU"; | ||
77 | return; | ||
78 | } | ||
79 | 99 | ||
80 | fprs = fprs_read(); | 100 | fprs = fprs_read(); |
81 | fprs_write(FPRS_FEF); | 101 | fprs_write(FPRS_FEF); |
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 | ||
101 | prom_peer_name: | 102 | prom_peer_name: |
102 | .asciz "peer" | 103 | .asciz "peer" |
103 | prom_compatible_name: | 104 | prom_compatible_name: |
@@ -106,6 +107,8 @@ prom_finddev_name: | |||
106 | .asciz "finddevice" | 107 | .asciz "finddevice" |
107 | prom_chosen_path: | 108 | prom_chosen_path: |
108 | .asciz "/chosen" | 109 | .asciz "/chosen" |
110 | prom_cpu_path: | ||
111 | .asciz "/cpu" | ||
109 | prom_getprop_name: | 112 | prom_getprop_name: |
110 | .asciz "getprop" | 113 | .asciz "getprop" |
111 | prom_mmu_name: | 114 | prom_mmu_name: |
@@ -120,9 +123,13 @@ prom_unmap_name: | |||
120 | .asciz "unmap" | 123 | .asciz "unmap" |
121 | prom_sun4v_name: | 124 | prom_sun4v_name: |
122 | .asciz "sun4v" | 125 | .asciz "sun4v" |
126 | prom_niagara_prefix: | ||
127 | .asciz "SUNW,UltraSPARC-T" | ||
123 | .align 4 | 128 | .align 4 |
124 | prom_root_compatible: | 129 | prom_root_compatible: |
125 | .skip 64 | 130 | .skip 64 |
131 | prom_cpu_compatible: | ||
132 | .skip 64 | ||
126 | prom_root_node: | 133 | prom_root_node: |
127 | .word 0 | 134 | .word 0 |
128 | prom_mmu_ihandle_cache: | 135 | prom_mmu_ihandle_cache: |
@@ -138,6 +145,8 @@ prom_boot_mapping_phys_low: | |||
138 | .xword 0 | 145 | .xword 0 |
139 | is_sun4v: | 146 | is_sun4v: |
140 | .word 0 | 147 | .word 0 |
148 | sun4v_chip_type: | ||
149 | .word SUN4V_CHIP_INVALID | ||
141 | 1: | 150 | 1: |
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 |
299 | 1: ldub [%g7], %g2 | 308 | 90: 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 | ||
313 | 2: | 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 | ||
371 | 90: 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 | ||
389 | 4: | ||
390 | mov SUN4V_CHIP_UNKNOWN, %g4 | ||
391 | 5: sethi %hi(sun4v_chip_type), %g2 | ||
392 | or %g2, %lo(sun4v_chip_type), %g2 | ||
393 | stw %g4, [%g2] | ||
394 | |||
395 | 80: | ||
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 | |||
516 | niagara_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 | ||
524 | 80: | ||
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/hvtramp.S b/arch/sparc64/kernel/hvtramp.S index a55c252e18cc..b692e044a463 100644 --- a/arch/sparc64/kernel/hvtramp.S +++ b/arch/sparc64/kernel/hvtramp.S | |||
@@ -115,11 +115,8 @@ hv_cpu_startup: | |||
115 | call hard_smp_processor_id | 115 | call hard_smp_processor_id |
116 | nop | 116 | nop |
117 | 117 | ||
118 | mov %o0, %o1 | 118 | call sun4v_register_mondo_queues |
119 | mov 0, %o0 | 119 | nop |
120 | mov 0, %o2 | ||
121 | call sun4v_init_mondo_queues | ||
122 | mov 1, %o3 | ||
123 | 120 | ||
124 | call init_cur_cpu_trap | 121 | call init_cur_cpu_trap |
125 | mov %g6, %o0 | 122 | mov %g6, %o0 |
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index db31bf6b42db..384abf410cf0 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
@@ -929,7 +929,7 @@ static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type | |||
929 | } | 929 | } |
930 | } | 930 | } |
931 | 931 | ||
932 | static void __cpuinit sun4v_register_mondo_queues(int this_cpu) | 932 | void __cpuinit sun4v_register_mondo_queues(int this_cpu) |
933 | { | 933 | { |
934 | struct trap_per_cpu *tb = &trap_block[this_cpu]; | 934 | struct trap_per_cpu *tb = &trap_block[this_cpu]; |
935 | 935 | ||
@@ -943,20 +943,10 @@ static void __cpuinit sun4v_register_mondo_queues(int this_cpu) | |||
943 | tb->nonresum_qmask); | 943 | tb->nonresum_qmask); |
944 | } | 944 | } |
945 | 945 | ||
946 | static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) | 946 | static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask) |
947 | { | 947 | { |
948 | unsigned long size = PAGE_ALIGN(qmask + 1); | 948 | unsigned long size = PAGE_ALIGN(qmask + 1); |
949 | unsigned long order = get_order(size); | 949 | void *p = __alloc_bootmem_low(size, size, 0); |
950 | void *p = NULL; | ||
951 | |||
952 | if (use_bootmem) { | ||
953 | p = __alloc_bootmem_low(size, size, 0); | ||
954 | } else { | ||
955 | struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); | ||
956 | if (page) | ||
957 | p = page_address(page); | ||
958 | } | ||
959 | |||
960 | if (!p) { | 950 | if (!p) { |
961 | prom_printf("SUN4V: Error, cannot allocate mondo queue.\n"); | 951 | prom_printf("SUN4V: Error, cannot allocate mondo queue.\n"); |
962 | prom_halt(); | 952 | prom_halt(); |
@@ -965,19 +955,10 @@ static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask | |||
965 | *pa_ptr = __pa(p); | 955 | *pa_ptr = __pa(p); |
966 | } | 956 | } |
967 | 957 | ||
968 | static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) | 958 | static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask) |
969 | { | 959 | { |
970 | unsigned long size = PAGE_ALIGN(qmask + 1); | 960 | unsigned long size = PAGE_ALIGN(qmask + 1); |
971 | unsigned long order = get_order(size); | 961 | void *p = __alloc_bootmem_low(size, size, 0); |
972 | void *p = NULL; | ||
973 | |||
974 | if (use_bootmem) { | ||
975 | p = __alloc_bootmem_low(size, size, 0); | ||
976 | } else { | ||
977 | struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); | ||
978 | if (page) | ||
979 | p = page_address(page); | ||
980 | } | ||
981 | 962 | ||
982 | if (!p) { | 963 | if (!p) { |
983 | prom_printf("SUN4V: Error, cannot allocate kbuf page.\n"); | 964 | prom_printf("SUN4V: Error, cannot allocate kbuf page.\n"); |
@@ -987,18 +968,14 @@ static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, | |||
987 | *pa_ptr = __pa(p); | 968 | *pa_ptr = __pa(p); |
988 | } | 969 | } |
989 | 970 | ||
990 | static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem) | 971 | static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb) |
991 | { | 972 | { |
992 | #ifdef CONFIG_SMP | 973 | #ifdef CONFIG_SMP |
993 | void *page; | 974 | void *page; |
994 | 975 | ||
995 | BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); | 976 | BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); |
996 | 977 | ||
997 | if (use_bootmem) | 978 | page = alloc_bootmem_low_pages(PAGE_SIZE); |
998 | page = alloc_bootmem_low_pages(PAGE_SIZE); | ||
999 | else | ||
1000 | page = (void *) get_zeroed_page(GFP_ATOMIC); | ||
1001 | |||
1002 | if (!page) { | 979 | if (!page) { |
1003 | prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); | 980 | prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); |
1004 | prom_halt(); | 981 | prom_halt(); |
@@ -1009,30 +986,27 @@ static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_ | |||
1009 | #endif | 986 | #endif |
1010 | } | 987 | } |
1011 | 988 | ||
1012 | /* Allocate and register the mondo and error queues for this cpu. */ | 989 | /* Allocate mondo and error queues for all possible cpus. */ |
1013 | void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load) | 990 | static void __init sun4v_init_mondo_queues(void) |
1014 | { | 991 | { |
1015 | struct trap_per_cpu *tb = &trap_block[cpu]; | 992 | int cpu; |
1016 | 993 | ||
1017 | if (alloc) { | 994 | for_each_possible_cpu(cpu) { |
1018 | alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem); | 995 | struct trap_per_cpu *tb = &trap_block[cpu]; |
1019 | alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem); | ||
1020 | alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem); | ||
1021 | alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem); | ||
1022 | alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem); | ||
1023 | alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem); | ||
1024 | 996 | ||
1025 | init_cpu_send_mondo_info(tb, use_bootmem); | 997 | alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask); |
1026 | } | 998 | alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask); |
999 | alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask); | ||
1000 | alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask); | ||
1001 | alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask); | ||
1002 | alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, | ||
1003 | tb->nonresum_qmask); | ||
1027 | 1004 | ||
1028 | if (load) { | 1005 | init_cpu_send_mondo_info(tb); |
1029 | if (cpu != hard_smp_processor_id()) { | ||
1030 | prom_printf("SUN4V: init mondo on cpu %d not %d\n", | ||
1031 | cpu, hard_smp_processor_id()); | ||
1032 | prom_halt(); | ||
1033 | } | ||
1034 | sun4v_register_mondo_queues(cpu); | ||
1035 | } | 1006 | } |
1007 | |||
1008 | /* Load up the boot cpu's entries. */ | ||
1009 | sun4v_register_mondo_queues(hard_smp_processor_id()); | ||
1036 | } | 1010 | } |
1037 | 1011 | ||
1038 | static struct irqaction timer_irq_action = { | 1012 | static struct irqaction timer_irq_action = { |
@@ -1047,7 +1021,7 @@ void __init init_IRQ(void) | |||
1047 | memset(&ivector_table[0], 0, sizeof(ivector_table)); | 1021 | memset(&ivector_table[0], 0, sizeof(ivector_table)); |
1048 | 1022 | ||
1049 | if (tlb_type == hypervisor) | 1023 | if (tlb_type == hypervisor) |
1050 | sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1); | 1024 | sun4v_init_mondo_queues(); |
1051 | 1025 | ||
1052 | /* We need to clear any IRQ's pending in the soft interrupt | 1026 | /* We need to clear any IRQ's pending in the soft interrupt |
1053 | * registers, a spurious one could be left around from the | 1027 | * registers, a spurious one could be left around from the |
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index cce4d0ddf5d5..95059c2ec414 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c | |||
@@ -568,20 +568,6 @@ static void __init report_platform_properties(void) | |||
568 | mdesc_release(hp); | 568 | mdesc_release(hp); |
569 | } | 569 | } |
570 | 570 | ||
571 | static int inline find_in_proplist(const char *list, const char *match, int len) | ||
572 | { | ||
573 | while (len > 0) { | ||
574 | int l; | ||
575 | |||
576 | if (!strcmp(list, match)) | ||
577 | return 1; | ||
578 | l = strlen(list) + 1; | ||
579 | list += l; | ||
580 | len -= l; | ||
581 | } | ||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static void __devinit fill_in_one_cache(cpuinfo_sparc *c, | 571 | static void __devinit fill_in_one_cache(cpuinfo_sparc *c, |
586 | struct mdesc_handle *hp, | 572 | struct mdesc_handle *hp, |
587 | u64 mp) | 573 | u64 mp) |
@@ -596,10 +582,10 @@ static void __devinit fill_in_one_cache(cpuinfo_sparc *c, | |||
596 | 582 | ||
597 | switch (*level) { | 583 | switch (*level) { |
598 | case 1: | 584 | case 1: |
599 | if (find_in_proplist(type, "instn", type_len)) { | 585 | if (of_find_in_proplist(type, "instn", type_len)) { |
600 | c->icache_size = *size; | 586 | c->icache_size = *size; |
601 | c->icache_line_size = *line_size; | 587 | c->icache_line_size = *line_size; |
602 | } else if (find_in_proplist(type, "data", type_len)) { | 588 | } else if (of_find_in_proplist(type, "data", type_len)) { |
603 | c->dcache_size = *size; | 589 | c->dcache_size = *size; |
604 | c->dcache_line_size = *line_size; | 590 | c->dcache_line_size = *line_size; |
605 | } | 591 | } |
@@ -677,7 +663,7 @@ static void __devinit set_core_ids(struct mdesc_handle *hp) | |||
677 | continue; | 663 | continue; |
678 | 664 | ||
679 | type = mdesc_get_property(hp, mp, "type", &len); | 665 | type = mdesc_get_property(hp, mp, "type", &len); |
680 | if (!find_in_proplist(type, "instn", len)) | 666 | if (!of_find_in_proplist(type, "instn", len)) |
681 | continue; | 667 | continue; |
682 | 668 | ||
683 | mark_core_ids(hp, mp, idx); | 669 | mark_core_ids(hp, mp, idx); |
@@ -718,8 +704,8 @@ static void __devinit __set_proc_ids(struct mdesc_handle *hp, | |||
718 | int len; | 704 | int len; |
719 | 705 | ||
720 | type = mdesc_get_property(hp, mp, "type", &len); | 706 | type = mdesc_get_property(hp, mp, "type", &len); |
721 | if (!find_in_proplist(type, "int", len) && | 707 | if (!of_find_in_proplist(type, "int", len) && |
722 | !find_in_proplist(type, "integer", len)) | 708 | !of_find_in_proplist(type, "integer", len)) |
723 | continue; | 709 | continue; |
724 | 710 | ||
725 | mark_proc_ids(hp, mp, idx); | 711 | mark_proc_ids(hp, mp, idx); |
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index f4e0a9ad9be3..d1a78c976cef 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c | |||
@@ -107,6 +107,21 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len | |||
107 | } | 107 | } |
108 | EXPORT_SYMBOL(of_set_property); | 108 | EXPORT_SYMBOL(of_set_property); |
109 | 109 | ||
110 | int of_find_in_proplist(const char *list, const char *match, int len) | ||
111 | { | ||
112 | while (len > 0) { | ||
113 | int l; | ||
114 | |||
115 | if (!strcmp(list, match)) | ||
116 | return 1; | ||
117 | l = strlen(list) + 1; | ||
118 | list += l; | ||
119 | len -= l; | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | EXPORT_SYMBOL(of_find_in_proplist); | ||
124 | |||
110 | static unsigned int prom_early_allocated; | 125 | static unsigned int prom_early_allocated; |
111 | 126 | ||
112 | static void * __init prom_early_alloc(unsigned long size) | 127 | static void * __init prom_early_alloc(unsigned long size) |
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index b448d33321c6..b84c49e3697c 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -334,8 +334,6 @@ static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg) | |||
334 | } | 334 | } |
335 | #endif | 335 | #endif |
336 | 336 | ||
337 | extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load); | ||
338 | |||
339 | extern unsigned long sparc64_cpu_startup; | 337 | extern unsigned long sparc64_cpu_startup; |
340 | 338 | ||
341 | /* The OBP cpu startup callback truncates the 3rd arg cookie to | 339 | /* The OBP cpu startup callback truncates the 3rd arg cookie to |
@@ -359,9 +357,6 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) | |||
359 | cpu_new_thread = task_thread_info(p); | 357 | cpu_new_thread = task_thread_info(p); |
360 | 358 | ||
361 | if (tlb_type == hypervisor) { | 359 | if (tlb_type == hypervisor) { |
362 | /* Alloc the mondo queues, cpu will load them. */ | ||
363 | sun4v_init_mondo_queues(0, cpu, 1, 0); | ||
364 | |||
365 | #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) | 360 | #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) |
366 | if (ldom_domaining_enabled) | 361 | if (ldom_domaining_enabled) |
367 | ldom_startcpu_cpuid(cpu, | 362 | ldom_startcpu_cpuid(cpu, |
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); | |||
168 | EXPORT_SYMBOL(__flushw_user); | 168 | EXPORT_SYMBOL(__flushw_user); |
169 | 169 | ||
170 | EXPORT_SYMBOL(tlb_type); | 170 | EXPORT_SYMBOL(tlb_type); |
171 | EXPORT_SYMBOL(sun4v_chip_type); | ||
171 | EXPORT_SYMBOL(get_fb_unmapped_area); | 172 | EXPORT_SYMBOL(get_fb_unmapped_area); |
172 | EXPORT_SYMBOL(flush_icache_range); | 173 | EXPORT_SYMBOL(flush_icache_range); |
173 | 174 | ||
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index a4dc01a3d238..9448595f9063 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S | |||
@@ -366,11 +366,8 @@ after_lock_tlb: | |||
366 | call hard_smp_processor_id | 366 | call hard_smp_processor_id |
367 | nop | 367 | nop |
368 | 368 | ||
369 | mov %o0, %o1 | 369 | call sun4v_register_mondo_queues |
370 | mov 0, %o0 | 370 | nop |
371 | mov 0, %o2 | ||
372 | call sun4v_init_mondo_queues | ||
373 | mov 1, %o3 | ||
374 | 371 | ||
375 | 1: call init_cur_cpu_trap | 372 | 1: call init_cur_cpu_trap |
376 | ldx [%l0], %o0 | 373 | ldx [%l0], %o0 |
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c index 3685daf5157f..1550ac5673da 100644 --- a/arch/sparc64/kernel/vio.c +++ b/arch/sparc64/kernel/vio.c | |||
@@ -16,21 +16,6 @@ | |||
16 | #include <asm/mdesc.h> | 16 | #include <asm/mdesc.h> |
17 | #include <asm/vio.h> | 17 | #include <asm/vio.h> |
18 | 18 | ||
19 | static inline int find_in_proplist(const char *list, const char *match, | ||
20 | int len) | ||
21 | { | ||
22 | while (len > 0) { | ||
23 | int l; | ||
24 | |||
25 | if (!strcmp(list, match)) | ||
26 | return 1; | ||
27 | l = strlen(list) + 1; | ||
28 | list += l; | ||
29 | len -= l; | ||
30 | } | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static const struct vio_device_id *vio_match_device( | 19 | static const struct vio_device_id *vio_match_device( |
35 | const struct vio_device_id *matches, | 20 | const struct vio_device_id *matches, |
36 | const struct vio_dev *dev) | 21 | const struct vio_dev *dev) |
@@ -49,7 +34,7 @@ static const struct vio_device_id *vio_match_device( | |||
49 | 34 | ||
50 | if (matches->compat[0]) { | 35 | if (matches->compat[0]) { |
51 | match &= len && | 36 | match &= len && |
52 | find_in_proplist(compat, matches->compat, len); | 37 | of_find_in_proplist(compat, matches->compat, len); |
53 | } | 38 | } |
54 | if (match) | 39 | if (match) |
55 | return matches; | 40 | return matches; |
@@ -406,7 +391,7 @@ static int __init vio_init(void) | |||
406 | "property\n"); | 391 | "property\n"); |
407 | goto out_release; | 392 | goto out_release; |
408 | } | 393 | } |
409 | if (!find_in_proplist(compat, channel_devices_compat, len)) { | 394 | if (!of_find_in_proplist(compat, channel_devices_compat, len)) { |
410 | printk(KERN_ERR "VIO: Channel devices node lacks (%s) " | 395 | printk(KERN_ERR "VIO: Channel devices node lacks (%s) " |
411 | "compat entry.\n", channel_devices_compat); | 396 | "compat entry.\n", channel_devices_compat); |
412 | goto out_release; | 397 | goto out_release; |
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) \ | ||
8 | 98: x,y; \ | ||
9 | .section .fixup; \ | ||
10 | .align 4; \ | ||
11 | 99: 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 | ||
24 | GENmemset: /* %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 | ||
37 | GENbzero: | ||
38 | clr %o2 | ||
39 | 1: 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 | |||
49 | GENbzero_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 | ||
57 | 1: EX_ST(stba %o2, [%o0 + 0x00] %asi) | ||
58 | subcc %g1, 1, %g1 | ||
59 | bne,pt %xcc, 1b | ||
60 | add %o0, 1, %o0 | ||
61 | 2: 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 | ||
68 | 1: EX_ST(stxa %o2, [%o0 + 0x00] %asi) | ||
69 | subcc %g1, 8, %g1 | ||
70 | bne,pt %xcc, 1b | ||
71 | add %o0, 8, %o0 | ||
72 | |||
73 | GENbzero_pre_loop: | ||
74 | andn %o1, (64 - 1), %g1 | ||
75 | sub %o1, %g1, %o1 | ||
76 | GENbzero_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 | ||
92 | GENbzero_medium: | ||
93 | andncc %o1, 0x7, %g1 | ||
94 | be,pn %xcc, 2f | ||
95 | sub %o1, %g1, %o1 | ||
96 | 1: EX_ST(stxa %o2, [%o0 + 0x00] %asi) | ||
97 | subcc %g1, 8, %g1 | ||
98 | bne,pt %xcc, 1b | ||
99 | add %o0, 8, %o0 | ||
100 | 2: brz,pt %o1, GENbzero_done | ||
101 | nop | ||
102 | |||
103 | GENbzero_tiny: | ||
104 | 1: 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 | |||
111 | GENbzero_done: | ||
112 | wr %o5, 0x0, %asi | ||
113 | |||
114 | GENbzero_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 | ||
122 | GENclear_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 | ||
154 | generic_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) \ | ||
7 | 98: x; \ | ||
8 | .section .fixup; \ | ||
9 | .align 4; \ | ||
10 | 99: 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) \ | ||
7 | 98: x; \ | ||
8 | .section .fixup; \ | ||
9 | .align 4; \ | ||
10 | 99: 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 | ||
52 | FUNC_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 | ||
75 | 1: 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 | ||
84 | 1: 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 | ||
96 | 80: /* 0 < len <= 16 */ | ||
97 | andcc %o3, 0x3, %g0 | ||
98 | bne,pn %XCC, 90f | ||
99 | sub %o0, %o1, %o3 | ||
100 | |||
101 | 1: | ||
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 | |||
108 | 85: retl | ||
109 | mov EX_RETVAL(GLOBAL_SPARE), %o0 | ||
110 | |||
111 | .align 32 | ||
112 | 90: | ||
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 | |||
10 | GENcopy_user_page: | ||
11 | set PAGE_SIZE, %g7 | ||
12 | 1: 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 | |||
35 | GENclear_page: | ||
36 | GENclear_user_page: | ||
37 | set PAGE_SIZE, %g7 | ||
38 | 1: 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 | ||
71 | generic_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 | ||
27 | generic_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 | ||