aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-08-05 12:42:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-08-05 12:42:36 -0400
commit8cd290a07d095f3b354e3448bcd7757393c29cd5 (patch)
treeaf33cb7677646bc506f1fae34676834dc45584a4 /arch/sparc
parent07d952dc669bb70a9716a81e140e89b7d4969f09 (diff)
parent961f65fc41cdc1f9099a6075258816c0db98e390 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc: Size mondo queues more sanely. sparc: Access kernel TSB using physical addressing when possible. sparc: Fix __atomic_add_unless() return value. sparc: use kbuild-generic support for true asm-generic header files sparc: Use popc when possible for ffs/__ffs/ffz. sparc: Set reboot-cmd using reboot data hypervisor call if available. sparc: Add some missing hypervisor API groups. sparc: Use hweight64() in popc emulation. sparc: Use popc if possible for hweight routines. sparc: Minor tweaks to Niagara page copy/clear. sparc: Sanitize cpu feature detection and reporting.
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/include/asm/Kbuild5
-rw-r--r--arch/sparc/include/asm/bitops_64.h49
-rw-r--r--arch/sparc/include/asm/div64.h1
-rw-r--r--arch/sparc/include/asm/elf_64.h65
-rw-r--r--arch/sparc/include/asm/hypervisor.h13
-rw-r--r--arch/sparc/include/asm/irq_regs.h1
-rw-r--r--arch/sparc/include/asm/local.h6
-rw-r--r--arch/sparc/include/asm/local64.h1
-rw-r--r--arch/sparc/include/asm/tsb.h51
-rw-r--r--arch/sparc/kernel/cpu.c1
-rw-r--r--arch/sparc/kernel/ds.c30
-rw-r--r--arch/sparc/kernel/entry.h14
-rw-r--r--arch/sparc/kernel/head_64.S2
-rw-r--r--arch/sparc/kernel/hvapi.c6
-rw-r--r--arch/sparc/kernel/hvcalls.S7
-rw-r--r--arch/sparc/kernel/kernel.h15
-rw-r--r--arch/sparc/kernel/ktlb.S24
-rw-r--r--arch/sparc/kernel/mdesc.c30
-rw-r--r--arch/sparc/kernel/setup_64.c186
-rw-r--r--arch/sparc/kernel/sparc_ksyms_64.c11
-rw-r--r--arch/sparc/kernel/sstate.c9
-rw-r--r--arch/sparc/kernel/unaligned_64.c15
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S21
-rw-r--r--arch/sparc/lib/Makefile4
-rw-r--r--arch/sparc/lib/NG2page.S61
-rw-r--r--arch/sparc/lib/NGpage.S114
-rw-r--r--arch/sparc/lib/atomic32.c2
-rw-r--r--arch/sparc/lib/ffs.S84
-rw-r--r--arch/sparc/lib/hweight.S51
-rw-r--r--arch/sparc/mm/init_64.c40
30 files changed, 661 insertions, 258 deletions
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 3c93f08ce187..2c2e38821f60 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -16,3 +16,8 @@ header-y += traps.h
16header-y += uctx.h 16header-y += uctx.h
17header-y += utrap.h 17header-y += utrap.h
18header-y += watchdog.h 18header-y += watchdog.h
19
20generic-y += div64.h
21generic-y += local64.h
22generic-y += irq_regs.h
23generic-y += local.h
diff --git a/arch/sparc/include/asm/bitops_64.h b/arch/sparc/include/asm/bitops_64.h
index 325e295d60de..29011cc0e4be 100644
--- a/arch/sparc/include/asm/bitops_64.h
+++ b/arch/sparc/include/asm/bitops_64.h
@@ -26,61 +26,28 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
26#define smp_mb__before_clear_bit() barrier() 26#define smp_mb__before_clear_bit() barrier()
27#define smp_mb__after_clear_bit() barrier() 27#define smp_mb__after_clear_bit() barrier()
28 28
29#include <asm-generic/bitops/ffz.h>
30#include <asm-generic/bitops/__ffs.h>
31#include <asm-generic/bitops/fls.h> 29#include <asm-generic/bitops/fls.h>
32#include <asm-generic/bitops/__fls.h> 30#include <asm-generic/bitops/__fls.h>
33#include <asm-generic/bitops/fls64.h> 31#include <asm-generic/bitops/fls64.h>
34 32
35#ifdef __KERNEL__ 33#ifdef __KERNEL__
36 34
35extern int ffs(int x);
36extern unsigned long __ffs(unsigned long);
37
38#include <asm-generic/bitops/ffz.h>
37#include <asm-generic/bitops/sched.h> 39#include <asm-generic/bitops/sched.h>
38#include <asm-generic/bitops/ffs.h>
39 40
40/* 41/*
41 * hweightN: returns the hamming weight (i.e. the number 42 * hweightN: returns the hamming weight (i.e. the number
42 * of bits set) of a N-bit word 43 * of bits set) of a N-bit word
43 */ 44 */
44 45
45#ifdef ULTRA_HAS_POPULATION_COUNT 46extern unsigned long __arch_hweight64(__u64 w);
46 47extern unsigned int __arch_hweight32(unsigned int w);
47static inline unsigned int __arch_hweight64(unsigned long w) 48extern unsigned int __arch_hweight16(unsigned int w);
48{ 49extern unsigned int __arch_hweight8(unsigned int w);
49 unsigned int res;
50
51 __asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
52 return res;
53}
54
55static inline unsigned int __arch_hweight32(unsigned int w)
56{
57 unsigned int res;
58
59 __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
60 return res;
61}
62 50
63static inline unsigned int __arch_hweight16(unsigned int w)
64{
65 unsigned int res;
66
67 __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
68 return res;
69}
70
71static inline unsigned int __arch_hweight8(unsigned int w)
72{
73 unsigned int res;
74
75 __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
76 return res;
77}
78
79#else
80
81#include <asm-generic/bitops/arch_hweight.h>
82
83#endif
84#include <asm-generic/bitops/const_hweight.h> 51#include <asm-generic/bitops/const_hweight.h>
85#include <asm-generic/bitops/lock.h> 52#include <asm-generic/bitops/lock.h>
86#endif /* __KERNEL__ */ 53#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/div64.h b/arch/sparc/include/asm/div64.h
deleted file mode 100644
index 6cd978cefb28..000000000000
--- a/arch/sparc/include/asm/div64.h
+++ /dev/null
@@ -1 +0,0 @@
1#include <asm-generic/div64.h>
diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h
index 64f7a00b3747..7df8b7f544d4 100644
--- a/arch/sparc/include/asm/elf_64.h
+++ b/arch/sparc/include/asm/elf_64.h
@@ -59,15 +59,33 @@
59#define R_SPARC_6 45 59#define R_SPARC_6 45
60 60
61/* Bits present in AT_HWCAP, primarily for Sparc32. */ 61/* Bits present in AT_HWCAP, primarily for Sparc32. */
62 62#define HWCAP_SPARC_FLUSH 0x00000001
63#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ 63#define HWCAP_SPARC_STBAR 0x00000002
64#define HWCAP_SPARC_STBAR 2 64#define HWCAP_SPARC_SWAP 0x00000004
65#define HWCAP_SPARC_SWAP 4 65#define HWCAP_SPARC_MULDIV 0x00000008
66#define HWCAP_SPARC_MULDIV 8 66#define HWCAP_SPARC_V9 0x00000010
67#define HWCAP_SPARC_V9 16 67#define HWCAP_SPARC_ULTRA3 0x00000020
68#define HWCAP_SPARC_ULTRA3 32 68#define HWCAP_SPARC_BLKINIT 0x00000040
69#define HWCAP_SPARC_BLKINIT 64 69#define HWCAP_SPARC_N2 0x00000080
70#define HWCAP_SPARC_N2 128 70
71/* Solaris compatible AT_HWCAP bits. */
72#define AV_SPARC_MUL32 0x00000100 /* 32x32 multiply is efficient */
73#define AV_SPARC_DIV32 0x00000200 /* 32x32 divide is efficient */
74#define AV_SPARC_FSMULD 0x00000400 /* 'fsmuld' is efficient */
75#define AV_SPARC_V8PLUS 0x00000800 /* v9 insn available to 32bit */
76#define AV_SPARC_POPC 0x00001000 /* 'popc' is efficient */
77#define AV_SPARC_VIS 0x00002000 /* VIS insns available */
78#define AV_SPARC_VIS2 0x00004000 /* VIS2 insns available */
79#define AV_SPARC_ASI_BLK_INIT 0x00008000 /* block init ASIs available */
80#define AV_SPARC_FMAF 0x00010000 /* fused multiply-add */
81#define AV_SPARC_VIS3 0x00020000 /* VIS3 insns available */
82#define AV_SPARC_HPC 0x00040000 /* HPC insns available */
83#define AV_SPARC_RANDOM 0x00080000 /* 'random' insn available */
84#define AV_SPARC_TRANS 0x00100000 /* transaction insns available */
85#define AV_SPARC_FJFMAU 0x00200000 /* unfused multiply-add */
86#define AV_SPARC_IMA 0x00400000 /* integer multiply-add */
87#define AV_SPARC_ASI_CACHE_SPARING \
88 0x00800000 /* cache sparing ASIs available */
71 89
72#define CORE_DUMP_USE_REGSET 90#define CORE_DUMP_USE_REGSET
73 91
@@ -162,33 +180,8 @@ typedef struct {
162#define ELF_ET_DYN_BASE 0x0000010000000000UL 180#define ELF_ET_DYN_BASE 0x0000010000000000UL
163#define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL 181#define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL
164 182
165 183extern unsigned long sparc64_elf_hwcap;
166/* This yields a mask that user programs can use to figure out what 184#define ELF_HWCAP sparc64_elf_hwcap
167 instruction set this cpu supports. */
168
169/* On Ultra, we support all of the v8 capabilities. */
170static inline unsigned int sparc64_elf_hwcap(void)
171{
172 unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
173 HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
174 HWCAP_SPARC_V9);
175
176 if (tlb_type == cheetah || tlb_type == cheetah_plus)
177 cap |= HWCAP_SPARC_ULTRA3;
178 else if (tlb_type == hypervisor) {
179 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
180 sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
181 sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
182 cap |= HWCAP_SPARC_BLKINIT;
183 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
184 sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
185 cap |= HWCAP_SPARC_N2;
186 }
187
188 return cap;
189}
190
191#define ELF_HWCAP sparc64_elf_hwcap()
192 185
193/* This yields a string that ld.so will use to load implementation 186/* This yields a string that ld.so will use to load implementation
194 specific libraries for optimization. This is more specific in 187 specific libraries for optimization. This is more specific in
diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h
index 7a5f80df15d0..015a761eaa32 100644
--- a/arch/sparc/include/asm/hypervisor.h
+++ b/arch/sparc/include/asm/hypervisor.h
@@ -2927,6 +2927,13 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
2927#define HV_FAST_FIRE_GET_PERFREG 0x120 2927#define HV_FAST_FIRE_GET_PERFREG 0x120
2928#define HV_FAST_FIRE_SET_PERFREG 0x121 2928#define HV_FAST_FIRE_SET_PERFREG 0x121
2929 2929
2930#define HV_FAST_REBOOT_DATA_SET 0x172
2931
2932#ifndef __ASSEMBLY__
2933extern unsigned long sun4v_reboot_data_set(unsigned long ra,
2934 unsigned long len);
2935#endif
2936
2930/* Function numbers for HV_CORE_TRAP. */ 2937/* Function numbers for HV_CORE_TRAP. */
2931#define HV_CORE_SET_VER 0x00 2938#define HV_CORE_SET_VER 0x00
2932#define HV_CORE_PUTCHAR 0x01 2939#define HV_CORE_PUTCHAR 0x01
@@ -2940,11 +2947,17 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
2940#define HV_GRP_CORE 0x0001 2947#define HV_GRP_CORE 0x0001
2941#define HV_GRP_INTR 0x0002 2948#define HV_GRP_INTR 0x0002
2942#define HV_GRP_SOFT_STATE 0x0003 2949#define HV_GRP_SOFT_STATE 0x0003
2950#define HV_GRP_TM 0x0080
2943#define HV_GRP_PCI 0x0100 2951#define HV_GRP_PCI 0x0100
2944#define HV_GRP_LDOM 0x0101 2952#define HV_GRP_LDOM 0x0101
2945#define HV_GRP_SVC_CHAN 0x0102 2953#define HV_GRP_SVC_CHAN 0x0102
2946#define HV_GRP_NCS 0x0103 2954#define HV_GRP_NCS 0x0103
2947#define HV_GRP_RNG 0x0104 2955#define HV_GRP_RNG 0x0104
2956#define HV_GRP_PBOOT 0x0105
2957#define HV_GRP_TPM 0x0107
2958#define HV_GRP_SDIO 0x0108
2959#define HV_GRP_SDIO_ERR 0x0109
2960#define HV_GRP_REBOOT_DATA 0x0110
2948#define HV_GRP_NIAG_PERF 0x0200 2961#define HV_GRP_NIAG_PERF 0x0200
2949#define HV_GRP_FIRE_PERF 0x0201 2962#define HV_GRP_FIRE_PERF 0x0201
2950#define HV_GRP_N2_CPU 0x0202 2963#define HV_GRP_N2_CPU 0x0202
diff --git a/arch/sparc/include/asm/irq_regs.h b/arch/sparc/include/asm/irq_regs.h
deleted file mode 100644
index 3dd9c0b70270..000000000000
--- a/arch/sparc/include/asm/irq_regs.h
+++ /dev/null
@@ -1 +0,0 @@
1#include <asm-generic/irq_regs.h>
diff --git a/arch/sparc/include/asm/local.h b/arch/sparc/include/asm/local.h
deleted file mode 100644
index bc80815a435c..000000000000
--- a/arch/sparc/include/asm/local.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef _SPARC_LOCAL_H
2#define _SPARC_LOCAL_H
3
4#include <asm-generic/local.h>
5
6#endif
diff --git a/arch/sparc/include/asm/local64.h b/arch/sparc/include/asm/local64.h
deleted file mode 100644
index 36c93b5cc239..000000000000
--- a/arch/sparc/include/asm/local64.h
+++ /dev/null
@@ -1 +0,0 @@
1#include <asm-generic/local64.h>
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h
index 83c571d8c8a7..1a8afd1ad04f 100644
--- a/arch/sparc/include/asm/tsb.h
+++ b/arch/sparc/include/asm/tsb.h
@@ -133,29 +133,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
133 sub TSB, 0x8, TSB; \ 133 sub TSB, 0x8, TSB; \
134 TSB_STORE(TSB, TAG); 134 TSB_STORE(TSB, TAG);
135 135
136#define KTSB_LOAD_QUAD(TSB, REG) \
137 ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG;
138
139#define KTSB_STORE(ADDR, VAL) \
140 stxa VAL, [ADDR] ASI_N;
141
142#define KTSB_LOCK_TAG(TSB, REG1, REG2) \
14399: lduwa [TSB] ASI_N, REG1; \
144 sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\
145 andcc REG1, REG2, %g0; \
146 bne,pn %icc, 99b; \
147 nop; \
148 casa [TSB] ASI_N, REG1, REG2;\
149 cmp REG1, REG2; \
150 bne,pn %icc, 99b; \
151 nop; \
152
153#define KTSB_WRITE(TSB, TTE, TAG) \
154 add TSB, 0x8, TSB; \
155 stxa TTE, [TSB] ASI_N; \
156 sub TSB, 0x8, TSB; \
157 stxa TAG, [TSB] ASI_N;
158
159 /* Do a kernel page table walk. Leaves physical PTE pointer in 136 /* Do a kernel page table walk. Leaves physical PTE pointer in
160 * REG1. Jumps to FAIL_LABEL on early page table walk termination. 137 * REG1. Jumps to FAIL_LABEL on early page table walk termination.
161 * VADDR will not be clobbered, but REG2 will. 138 * VADDR will not be clobbered, but REG2 will.
@@ -239,6 +216,8 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
239 (KERNEL_TSB_SIZE_BYTES / 16) 216 (KERNEL_TSB_SIZE_BYTES / 16)
240#define KERNEL_TSB4M_NENTRIES 4096 217#define KERNEL_TSB4M_NENTRIES 4096
241 218
219#define KTSB_PHYS_SHIFT 15
220
242 /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL 221 /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
243 * on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries 222 * on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries
244 * and the found TTE will be left in REG1. REG3 and REG4 must 223 * and the found TTE will be left in REG1. REG3 and REG4 must
@@ -247,13 +226,22 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
247 * VADDR and TAG will be preserved and not clobbered by this macro. 226 * VADDR and TAG will be preserved and not clobbered by this macro.
248 */ 227 */
249#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ 228#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
250 sethi %hi(swapper_tsb), REG1; \ 229661: sethi %hi(swapper_tsb), REG1; \
251 or REG1, %lo(swapper_tsb), REG1; \ 230 or REG1, %lo(swapper_tsb), REG1; \
231 .section .swapper_tsb_phys_patch, "ax"; \
232 .word 661b; \
233 .previous; \
234661: nop; \
235 .section .tsb_ldquad_phys_patch, "ax"; \
236 .word 661b; \
237 sllx REG1, KTSB_PHYS_SHIFT, REG1; \
238 sllx REG1, KTSB_PHYS_SHIFT, REG1; \
239 .previous; \
252 srlx VADDR, PAGE_SHIFT, REG2; \ 240 srlx VADDR, PAGE_SHIFT, REG2; \
253 and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \ 241 and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
254 sllx REG2, 4, REG2; \ 242 sllx REG2, 4, REG2; \
255 add REG1, REG2, REG2; \ 243 add REG1, REG2, REG2; \
256 KTSB_LOAD_QUAD(REG2, REG3); \ 244 TSB_LOAD_QUAD(REG2, REG3); \
257 cmp REG3, TAG; \ 245 cmp REG3, TAG; \
258 be,a,pt %xcc, OK_LABEL; \ 246 be,a,pt %xcc, OK_LABEL; \
259 mov REG4, REG1; 247 mov REG4, REG1;
@@ -263,12 +251,21 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
263 * we can make use of that for the index computation. 251 * we can make use of that for the index computation.
264 */ 252 */
265#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ 253#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
266 sethi %hi(swapper_4m_tsb), REG1; \ 254661: sethi %hi(swapper_4m_tsb), REG1; \
267 or REG1, %lo(swapper_4m_tsb), REG1; \ 255 or REG1, %lo(swapper_4m_tsb), REG1; \
256 .section .swapper_4m_tsb_phys_patch, "ax"; \
257 .word 661b; \
258 .previous; \
259661: nop; \
260 .section .tsb_ldquad_phys_patch, "ax"; \
261 .word 661b; \
262 sllx REG1, KTSB_PHYS_SHIFT, REG1; \
263 sllx REG1, KTSB_PHYS_SHIFT, REG1; \
264 .previous; \
268 and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \ 265 and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
269 sllx REG2, 4, REG2; \ 266 sllx REG2, 4, REG2; \
270 add REG1, REG2, REG2; \ 267 add REG1, REG2, REG2; \
271 KTSB_LOAD_QUAD(REG2, REG3); \ 268 TSB_LOAD_QUAD(REG2, REG3); \
272 cmp REG3, TAG; \ 269 cmp REG3, TAG; \
273 be,a,pt %xcc, OK_LABEL; \ 270 be,a,pt %xcc, OK_LABEL; \
274 mov REG4, REG1; 271 mov REG4, REG1;
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 17cf290dc2bc..9810fd881058 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -396,6 +396,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
396 , cpu_data(0).clock_tick 396 , cpu_data(0).clock_tick
397#endif 397#endif
398 ); 398 );
399 cpucap_info(m);
399#ifdef CONFIG_SMP 400#ifdef CONFIG_SMP
400 smp_bogo(m); 401 smp_bogo(m);
401#endif 402#endif
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
index dd1342c0a3be..490e5418740d 100644
--- a/arch/sparc/kernel/ds.c
+++ b/arch/sparc/kernel/ds.c
@@ -15,12 +15,15 @@
15#include <linux/reboot.h> 15#include <linux/reboot.h>
16#include <linux/cpu.h> 16#include <linux/cpu.h>
17 17
18#include <asm/hypervisor.h>
18#include <asm/ldc.h> 19#include <asm/ldc.h>
19#include <asm/vio.h> 20#include <asm/vio.h>
20#include <asm/mdesc.h> 21#include <asm/mdesc.h>
21#include <asm/head.h> 22#include <asm/head.h>
22#include <asm/irq.h> 23#include <asm/irq.h>
23 24
25#include "kernel.h"
26
24#define DRV_MODULE_NAME "ds" 27#define DRV_MODULE_NAME "ds"
25#define PFX DRV_MODULE_NAME ": " 28#define PFX DRV_MODULE_NAME ": "
26#define DRV_MODULE_VERSION "1.0" 29#define DRV_MODULE_VERSION "1.0"
@@ -828,18 +831,32 @@ void ldom_set_var(const char *var, const char *value)
828 } 831 }
829} 832}
830 833
834static char full_boot_str[256] __attribute__((aligned(32)));
835static int reboot_data_supported;
836
831void ldom_reboot(const char *boot_command) 837void ldom_reboot(const char *boot_command)
832{ 838{
833 /* Don't bother with any of this if the boot_command 839 /* Don't bother with any of this if the boot_command
834 * is empty. 840 * is empty.
835 */ 841 */
836 if (boot_command && strlen(boot_command)) { 842 if (boot_command && strlen(boot_command)) {
837 char full_boot_str[256]; 843 unsigned long len;
838 844
839 strcpy(full_boot_str, "boot "); 845 strcpy(full_boot_str, "boot ");
840 strcpy(full_boot_str + strlen("boot "), boot_command); 846 strcpy(full_boot_str + strlen("boot "), boot_command);
847 len = strlen(full_boot_str);
841 848
842 ldom_set_var("reboot-command", full_boot_str); 849 if (reboot_data_supported) {
850 unsigned long ra = kimage_addr_to_ra(full_boot_str);
851 unsigned long hv_ret;
852
853 hv_ret = sun4v_reboot_data_set(ra, len);
854 if (hv_ret != HV_EOK)
855 pr_err("SUN4V: Unable to set reboot data "
856 "hv_ret=%lu\n", hv_ret);
857 } else {
858 ldom_set_var("reboot-command", full_boot_str);
859 }
843 } 860 }
844 sun4v_mach_sir(); 861 sun4v_mach_sir();
845} 862}
@@ -1237,6 +1254,15 @@ static struct vio_driver ds_driver = {
1237 1254
1238static int __init ds_init(void) 1255static int __init ds_init(void)
1239{ 1256{
1257 unsigned long hv_ret, major, minor;
1258
1259 hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
1260 if (hv_ret == HV_EOK) {
1261 pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
1262 major, minor);
1263 reboot_data_supported = 1;
1264 }
1265
1240 kthread_run(ds_thread, NULL, "kldomd"); 1266 kthread_run(ds_thread, NULL, "kldomd");
1241 1267
1242 return vio_register_driver(&ds_driver); 1268 return vio_register_driver(&ds_driver);
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index d1f1361c4167..e27f8ea8656e 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -42,6 +42,20 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
42extern void fpload(unsigned long *fpregs, unsigned long *fsr); 42extern void fpload(unsigned long *fpregs, unsigned long *fsr);
43 43
44#else /* CONFIG_SPARC32 */ 44#else /* CONFIG_SPARC32 */
45struct popc_3insn_patch_entry {
46 unsigned int addr;
47 unsigned int insns[3];
48};
49extern struct popc_3insn_patch_entry __popc_3insn_patch,
50 __popc_3insn_patch_end;
51
52struct popc_6insn_patch_entry {
53 unsigned int addr;
54 unsigned int insns[6];
55};
56extern struct popc_6insn_patch_entry __popc_6insn_patch,
57 __popc_6insn_patch_end;
58
45extern void __init per_cpu_patch(void); 59extern void __init per_cpu_patch(void);
46extern void __init sun4v_patch(void); 60extern void __init sun4v_patch(void);
47extern void __init boot_cpu_id_too_large(int cpu); 61extern void __init boot_cpu_id_too_large(int cpu);
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index c752603a7c0d..0eac1b2fc53d 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -559,7 +559,7 @@ niagara2_patch:
559 nop 559 nop
560 call niagara_patch_bzero 560 call niagara_patch_bzero
561 nop 561 nop
562 call niagara2_patch_pageops 562 call niagara_patch_pageops
563 nop 563 nop
564 564
565 ba,a,pt %xcc, 80f 565 ba,a,pt %xcc, 80f
diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c
index d306e648c33c..c2d055d8ba9e 100644
--- a/arch/sparc/kernel/hvapi.c
+++ b/arch/sparc/kernel/hvapi.c
@@ -28,11 +28,17 @@ static struct api_info api_table[] = {
28 { .group = HV_GRP_CORE, .flags = FLAG_PRE_API }, 28 { .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
29 { .group = HV_GRP_INTR, }, 29 { .group = HV_GRP_INTR, },
30 { .group = HV_GRP_SOFT_STATE, }, 30 { .group = HV_GRP_SOFT_STATE, },
31 { .group = HV_GRP_TM, },
31 { .group = HV_GRP_PCI, .flags = FLAG_PRE_API }, 32 { .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
32 { .group = HV_GRP_LDOM, }, 33 { .group = HV_GRP_LDOM, },
33 { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API }, 34 { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
34 { .group = HV_GRP_NCS, .flags = FLAG_PRE_API }, 35 { .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
35 { .group = HV_GRP_RNG, }, 36 { .group = HV_GRP_RNG, },
37 { .group = HV_GRP_PBOOT, },
38 { .group = HV_GRP_TPM, },
39 { .group = HV_GRP_SDIO, },
40 { .group = HV_GRP_SDIO_ERR, },
41 { .group = HV_GRP_REBOOT_DATA, },
36 { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API }, 42 { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
37 { .group = HV_GRP_FIRE_PERF, }, 43 { .group = HV_GRP_FIRE_PERF, },
38 { .group = HV_GRP_N2_CPU, }, 44 { .group = HV_GRP_N2_CPU, },
diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S
index 8a5f35ffb15e..58d60de4d65b 100644
--- a/arch/sparc/kernel/hvcalls.S
+++ b/arch/sparc/kernel/hvcalls.S
@@ -798,3 +798,10 @@ ENTRY(sun4v_niagara2_setperf)
798 retl 798 retl
799 nop 799 nop
800ENDPROC(sun4v_niagara2_setperf) 800ENDPROC(sun4v_niagara2_setperf)
801
802ENTRY(sun4v_reboot_data_set)
803 mov HV_FAST_REBOOT_DATA_SET, %o5
804 ta HV_FAST_TRAP
805 retl
806 nop
807ENDPROC(sun4v_reboot_data_set)
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 6f6544cfa0ef..fd6c36b1df74 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -4,12 +4,27 @@
4#include <linux/interrupt.h> 4#include <linux/interrupt.h>
5 5
6#include <asm/traps.h> 6#include <asm/traps.h>
7#include <asm/head.h>
8#include <asm/io.h>
7 9
8/* cpu.c */ 10/* cpu.c */
9extern const char *sparc_pmu_type; 11extern const char *sparc_pmu_type;
10extern unsigned int fsr_storage; 12extern unsigned int fsr_storage;
11extern int ncpus_probed; 13extern int ncpus_probed;
12 14
15#ifdef CONFIG_SPARC64
16/* setup_64.c */
17struct seq_file;
18extern void cpucap_info(struct seq_file *);
19
20static inline unsigned long kimage_addr_to_ra(const char *p)
21{
22 unsigned long val = (unsigned long) p;
23
24 return kern_base + (val - KERNBASE);
25}
26#endif
27
13#ifdef CONFIG_SPARC32 28#ifdef CONFIG_SPARC32
14/* cpu.c */ 29/* cpu.c */
15extern void cpu_probe(void); 30extern void cpu_probe(void);
diff --git a/arch/sparc/kernel/ktlb.S b/arch/sparc/kernel/ktlb.S
index 1d361477d7d6..79f310364849 100644
--- a/arch/sparc/kernel/ktlb.S
+++ b/arch/sparc/kernel/ktlb.S
@@ -47,16 +47,16 @@ kvmap_itlb_tsb_miss:
47kvmap_itlb_vmalloc_addr: 47kvmap_itlb_vmalloc_addr:
48 KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath) 48 KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
49 49
50 KTSB_LOCK_TAG(%g1, %g2, %g7) 50 TSB_LOCK_TAG(%g1, %g2, %g7)
51 51
52 /* Load and check PTE. */ 52 /* Load and check PTE. */
53 ldxa [%g5] ASI_PHYS_USE_EC, %g5 53 ldxa [%g5] ASI_PHYS_USE_EC, %g5
54 mov 1, %g7 54 mov 1, %g7
55 sllx %g7, TSB_TAG_INVALID_BIT, %g7 55 sllx %g7, TSB_TAG_INVALID_BIT, %g7
56 brgez,a,pn %g5, kvmap_itlb_longpath 56 brgez,a,pn %g5, kvmap_itlb_longpath
57 KTSB_STORE(%g1, %g7) 57 TSB_STORE(%g1, %g7)
58 58
59 KTSB_WRITE(%g1, %g5, %g6) 59 TSB_WRITE(%g1, %g5, %g6)
60 60
61 /* fallthrough to TLB load */ 61 /* fallthrough to TLB load */
62 62
@@ -102,9 +102,9 @@ kvmap_itlb_longpath:
102kvmap_itlb_obp: 102kvmap_itlb_obp:
103 OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath) 103 OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
104 104
105 KTSB_LOCK_TAG(%g1, %g2, %g7) 105 TSB_LOCK_TAG(%g1, %g2, %g7)
106 106
107 KTSB_WRITE(%g1, %g5, %g6) 107 TSB_WRITE(%g1, %g5, %g6)
108 108
109 ba,pt %xcc, kvmap_itlb_load 109 ba,pt %xcc, kvmap_itlb_load
110 nop 110 nop
@@ -112,17 +112,17 @@ kvmap_itlb_obp:
112kvmap_dtlb_obp: 112kvmap_dtlb_obp:
113 OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath) 113 OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
114 114
115 KTSB_LOCK_TAG(%g1, %g2, %g7) 115 TSB_LOCK_TAG(%g1, %g2, %g7)
116 116
117 KTSB_WRITE(%g1, %g5, %g6) 117 TSB_WRITE(%g1, %g5, %g6)
118 118
119 ba,pt %xcc, kvmap_dtlb_load 119 ba,pt %xcc, kvmap_dtlb_load
120 nop 120 nop
121 121
122 .align 32 122 .align 32
123kvmap_dtlb_tsb4m_load: 123kvmap_dtlb_tsb4m_load:
124 KTSB_LOCK_TAG(%g1, %g2, %g7) 124 TSB_LOCK_TAG(%g1, %g2, %g7)
125 KTSB_WRITE(%g1, %g5, %g6) 125 TSB_WRITE(%g1, %g5, %g6)
126 ba,pt %xcc, kvmap_dtlb_load 126 ba,pt %xcc, kvmap_dtlb_load
127 nop 127 nop
128 128
@@ -222,16 +222,16 @@ kvmap_linear_patch:
222kvmap_dtlb_vmalloc_addr: 222kvmap_dtlb_vmalloc_addr:
223 KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath) 223 KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
224 224
225 KTSB_LOCK_TAG(%g1, %g2, %g7) 225 TSB_LOCK_TAG(%g1, %g2, %g7)
226 226
227 /* Load and check PTE. */ 227 /* Load and check PTE. */
228 ldxa [%g5] ASI_PHYS_USE_EC, %g5 228 ldxa [%g5] ASI_PHYS_USE_EC, %g5
229 mov 1, %g7 229 mov 1, %g7
230 sllx %g7, TSB_TAG_INVALID_BIT, %g7 230 sllx %g7, TSB_TAG_INVALID_BIT, %g7
231 brgez,a,pn %g5, kvmap_dtlb_longpath 231 brgez,a,pn %g5, kvmap_dtlb_longpath
232 KTSB_STORE(%g1, %g7) 232 TSB_STORE(%g1, %g7)
233 233
234 KTSB_WRITE(%g1, %g5, %g6) 234 TSB_WRITE(%g1, %g5, %g6)
235 235
236 /* fallthrough to TLB load */ 236 /* fallthrough to TLB load */
237 237
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index 42f28c7420e1..acaebb63c4fd 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -508,6 +508,8 @@ const char *mdesc_node_name(struct mdesc_handle *hp, u64 node)
508} 508}
509EXPORT_SYMBOL(mdesc_node_name); 509EXPORT_SYMBOL(mdesc_node_name);
510 510
511static u64 max_cpus = 64;
512
511static void __init report_platform_properties(void) 513static void __init report_platform_properties(void)
512{ 514{
513 struct mdesc_handle *hp = mdesc_grab(); 515 struct mdesc_handle *hp = mdesc_grab();
@@ -543,8 +545,10 @@ static void __init report_platform_properties(void)
543 if (v) 545 if (v)
544 printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v); 546 printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v);
545 v = mdesc_get_property(hp, pn, "max-cpus", NULL); 547 v = mdesc_get_property(hp, pn, "max-cpus", NULL);
546 if (v) 548 if (v) {
547 printk("PLATFORM: max-cpus [%llu]\n", *v); 549 max_cpus = *v;
550 printk("PLATFORM: max-cpus [%llu]\n", max_cpus);
551 }
548 552
549#ifdef CONFIG_SMP 553#ifdef CONFIG_SMP
550 { 554 {
@@ -715,7 +719,7 @@ static void __cpuinit set_proc_ids(struct mdesc_handle *hp)
715} 719}
716 720
717static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask, 721static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
718 unsigned char def) 722 unsigned long def, unsigned long max)
719{ 723{
720 u64 val; 724 u64 val;
721 725
@@ -726,6 +730,9 @@ static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
726 if (!val || val >= 64) 730 if (!val || val >= 64)
727 goto use_default; 731 goto use_default;
728 732
733 if (val > max)
734 val = max;
735
729 *mask = ((1U << val) * 64U) - 1U; 736 *mask = ((1U << val) * 64U) - 1U;
730 return; 737 return;
731 738
@@ -736,19 +743,28 @@ use_default:
736static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp, 743static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
737 struct trap_per_cpu *tb) 744 struct trap_per_cpu *tb)
738{ 745{
746 static int printed;
739 const u64 *val; 747 const u64 *val;
740 748
741 val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL); 749 val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
742 get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7); 750 get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7, ilog2(max_cpus * 2));
743 751
744 val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL); 752 val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
745 get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7); 753 get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7, 8);
746 754
747 val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL); 755 val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
748 get_one_mondo_bits(val, &tb->resum_qmask, 6); 756 get_one_mondo_bits(val, &tb->resum_qmask, 6, 7);
749 757
750 val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL); 758 val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
751 get_one_mondo_bits(val, &tb->nonresum_qmask, 2); 759 get_one_mondo_bits(val, &tb->nonresum_qmask, 2, 2);
760 if (!printed++) {
761 pr_info("SUN4V: Mondo queue sizes "
762 "[cpu(%u) dev(%u) r(%u) nr(%u)]\n",
763 tb->cpu_mondo_qmask + 1,
764 tb->dev_mondo_qmask + 1,
765 tb->resum_qmask + 1,
766 tb->nonresum_qmask + 1);
767 }
752} 768}
753 769
754static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask) 770static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index c4dd0999da86..3e9daea1653d 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -29,6 +29,7 @@
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/cpu.h> 30#include <linux/cpu.h>
31#include <linux/initrd.h> 31#include <linux/initrd.h>
32#include <linux/module.h>
32 33
33#include <asm/system.h> 34#include <asm/system.h>
34#include <asm/io.h> 35#include <asm/io.h>
@@ -46,6 +47,8 @@
46#include <asm/mmu.h> 47#include <asm/mmu.h>
47#include <asm/ns87303.h> 48#include <asm/ns87303.h>
48#include <asm/btext.h> 49#include <asm/btext.h>
50#include <asm/elf.h>
51#include <asm/mdesc.h>
49 52
50#ifdef CONFIG_IP_PNP 53#ifdef CONFIG_IP_PNP
51#include <net/ipconfig.h> 54#include <net/ipconfig.h>
@@ -269,6 +272,40 @@ void __init sun4v_patch(void)
269 sun4v_hvapi_init(); 272 sun4v_hvapi_init();
270} 273}
271 274
275static void __init popc_patch(void)
276{
277 struct popc_3insn_patch_entry *p3;
278 struct popc_6insn_patch_entry *p6;
279
280 p3 = &__popc_3insn_patch;
281 while (p3 < &__popc_3insn_patch_end) {
282 unsigned long i, addr = p3->addr;
283
284 for (i = 0; i < 3; i++) {
285 *(unsigned int *) (addr + (i * 4)) = p3->insns[i];
286 wmb();
287 __asm__ __volatile__("flush %0"
288 : : "r" (addr + (i * 4)));
289 }
290
291 p3++;
292 }
293
294 p6 = &__popc_6insn_patch;
295 while (p6 < &__popc_6insn_patch_end) {
296 unsigned long i, addr = p6->addr;
297
298 for (i = 0; i < 6; i++) {
299 *(unsigned int *) (addr + (i * 4)) = p6->insns[i];
300 wmb();
301 __asm__ __volatile__("flush %0"
302 : : "r" (addr + (i * 4)));
303 }
304
305 p6++;
306 }
307}
308
272#ifdef CONFIG_SMP 309#ifdef CONFIG_SMP
273void __init boot_cpu_id_too_large(int cpu) 310void __init boot_cpu_id_too_large(int cpu)
274{ 311{
@@ -278,6 +315,154 @@ void __init boot_cpu_id_too_large(int cpu)
278} 315}
279#endif 316#endif
280 317
318/* On Ultra, we support all of the v8 capabilities. */
319unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
320 HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
321 HWCAP_SPARC_V9);
322EXPORT_SYMBOL(sparc64_elf_hwcap);
323
324static const char *hwcaps[] = {
325 "flush", "stbar", "swap", "muldiv", "v9",
326 "ultra3", "blkinit", "n2",
327
328 /* These strings are as they appear in the machine description
329 * 'hwcap-list' property for cpu nodes.
330 */
331 "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
332 "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
333 "ima", "cspare",
334};
335
336void cpucap_info(struct seq_file *m)
337{
338 unsigned long caps = sparc64_elf_hwcap;
339 int i, printed = 0;
340
341 seq_puts(m, "cpucaps\t\t: ");
342 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
343 unsigned long bit = 1UL << i;
344 if (caps & bit) {
345 seq_printf(m, "%s%s",
346 printed ? "," : "", hwcaps[i]);
347 printed++;
348 }
349 }
350 seq_putc(m, '\n');
351}
352
353static void __init report_hwcaps(unsigned long caps)
354{
355 int i, printed = 0;
356
357 printk(KERN_INFO "CPU CAPS: [");
358 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
359 unsigned long bit = 1UL << i;
360 if (caps & bit) {
361 printk(KERN_CONT "%s%s",
362 printed ? "," : "", hwcaps[i]);
363 if (++printed == 8) {
364 printk(KERN_CONT "]\n");
365 printk(KERN_INFO "CPU CAPS: [");
366 printed = 0;
367 }
368 }
369 }
370 printk(KERN_CONT "]\n");
371}
372
373static unsigned long __init mdesc_cpu_hwcap_list(void)
374{
375 struct mdesc_handle *hp;
376 unsigned long caps = 0;
377 const char *prop;
378 int len;
379 u64 pn;
380
381 hp = mdesc_grab();
382 if (!hp)
383 return 0;
384
385 pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu");
386 if (pn == MDESC_NODE_NULL)
387 goto out;
388
389 prop = mdesc_get_property(hp, pn, "hwcap-list", &len);
390 if (!prop)
391 goto out;
392
393 while (len) {
394 int i, plen;
395
396 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
397 unsigned long bit = 1UL << i;
398
399 if (!strcmp(prop, hwcaps[i])) {
400 caps |= bit;
401 break;
402 }
403 }
404
405 plen = strlen(prop) + 1;
406 prop += plen;
407 len -= plen;
408 }
409
410out:
411 mdesc_release(hp);
412 return caps;
413}
414
415/* This yields a mask that user programs can use to figure out what
416 * instruction set this cpu supports.
417 */
418static void __init init_sparc64_elf_hwcap(void)
419{
420 unsigned long cap = sparc64_elf_hwcap;
421 unsigned long mdesc_caps;
422
423 if (tlb_type == cheetah || tlb_type == cheetah_plus)
424 cap |= HWCAP_SPARC_ULTRA3;
425 else if (tlb_type == hypervisor) {
426 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
427 sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
428 sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
429 cap |= HWCAP_SPARC_BLKINIT;
430 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
431 sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
432 cap |= HWCAP_SPARC_N2;
433 }
434
435 cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS);
436
437 mdesc_caps = mdesc_cpu_hwcap_list();
438 if (!mdesc_caps) {
439 if (tlb_type == spitfire)
440 cap |= AV_SPARC_VIS;
441 if (tlb_type == cheetah || tlb_type == cheetah_plus)
442 cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
443 if (tlb_type == cheetah_plus)
444 cap |= AV_SPARC_POPC;
445 if (tlb_type == hypervisor) {
446 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
447 cap |= AV_SPARC_ASI_BLK_INIT;
448 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
449 sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
450 cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
451 AV_SPARC_ASI_BLK_INIT |
452 AV_SPARC_POPC);
453 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
454 cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
455 AV_SPARC_FMAF);
456 }
457 }
458 sparc64_elf_hwcap = cap | mdesc_caps;
459
460 report_hwcaps(sparc64_elf_hwcap);
461
462 if (sparc64_elf_hwcap & AV_SPARC_POPC)
463 popc_patch();
464}
465
281void __init setup_arch(char **cmdline_p) 466void __init setup_arch(char **cmdline_p)
282{ 467{
283 /* Initialize PROM console and command line. */ 468 /* Initialize PROM console and command line. */
@@ -337,6 +522,7 @@ void __init setup_arch(char **cmdline_p)
337 init_cur_cpu_trap(current_thread_info()); 522 init_cur_cpu_trap(current_thread_info());
338 523
339 paging_init(); 524 paging_init();
525 init_sparc64_elf_hwcap();
340} 526}
341 527
342extern int stop_a_enabled; 528extern int stop_a_enabled;
diff --git a/arch/sparc/kernel/sparc_ksyms_64.c b/arch/sparc/kernel/sparc_ksyms_64.c
index 372ad59c4cba..83b47ab02d96 100644
--- a/arch/sparc/kernel/sparc_ksyms_64.c
+++ b/arch/sparc/kernel/sparc_ksyms_64.c
@@ -8,6 +8,7 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/pci.h> 9#include <linux/pci.h>
10#include <linux/init.h> 10#include <linux/init.h>
11#include <linux/bitops.h>
11 12
12#include <asm/system.h> 13#include <asm/system.h>
13#include <asm/cpudata.h> 14#include <asm/cpudata.h>
@@ -38,5 +39,15 @@ EXPORT_SYMBOL(sun4v_niagara_setperf);
38EXPORT_SYMBOL(sun4v_niagara2_getperf); 39EXPORT_SYMBOL(sun4v_niagara2_getperf);
39EXPORT_SYMBOL(sun4v_niagara2_setperf); 40EXPORT_SYMBOL(sun4v_niagara2_setperf);
40 41
42/* from hweight.S */
43EXPORT_SYMBOL(__arch_hweight8);
44EXPORT_SYMBOL(__arch_hweight16);
45EXPORT_SYMBOL(__arch_hweight32);
46EXPORT_SYMBOL(__arch_hweight64);
47
48/* from ffs_ffz.S */
49EXPORT_SYMBOL(ffs);
50EXPORT_SYMBOL(__ffs);
51
41/* Exporting a symbol from /init/main.c */ 52/* Exporting a symbol from /init/main.c */
42EXPORT_SYMBOL(saved_command_line); 53EXPORT_SYMBOL(saved_command_line);
diff --git a/arch/sparc/kernel/sstate.c b/arch/sparc/kernel/sstate.c
index 8cdbe5946b43..c59af546f522 100644
--- a/arch/sparc/kernel/sstate.c
+++ b/arch/sparc/kernel/sstate.c
@@ -14,14 +14,9 @@
14#include <asm/head.h> 14#include <asm/head.h>
15#include <asm/io.h> 15#include <asm/io.h>
16 16
17static int hv_supports_soft_state; 17#include "kernel.h"
18
19static unsigned long kimage_addr_to_ra(const char *p)
20{
21 unsigned long val = (unsigned long) p;
22 18
23 return kern_base + (val - KERNBASE); 19static int hv_supports_soft_state;
24}
25 20
26static void do_set_sstate(unsigned long state, const char *msg) 21static void do_set_sstate(unsigned long state, const char *msg)
27{ 22{
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c
index 35cff1673aa4..76e4ac1a13e1 100644
--- a/arch/sparc/kernel/unaligned_64.c
+++ b/arch/sparc/kernel/unaligned_64.c
@@ -22,6 +22,7 @@
22#include <linux/bitops.h> 22#include <linux/bitops.h>
23#include <linux/perf_event.h> 23#include <linux/perf_event.h>
24#include <linux/ratelimit.h> 24#include <linux/ratelimit.h>
25#include <linux/bitops.h>
25#include <asm/fpumacro.h> 26#include <asm/fpumacro.h>
26 27
27enum direction { 28enum direction {
@@ -373,16 +374,11 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
373 } 374 }
374} 375}
375 376
376static char popc_helper[] = {
3770, 1, 1, 2, 1, 2, 2, 3,
3781, 2, 2, 3, 2, 3, 3, 4,
379};
380
381int handle_popc(u32 insn, struct pt_regs *regs) 377int handle_popc(u32 insn, struct pt_regs *regs)
382{ 378{
383 u64 value;
384 int ret, i, rd = ((insn >> 25) & 0x1f);
385 int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; 379 int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
380 int ret, rd = ((insn >> 25) & 0x1f);
381 u64 value;
386 382
387 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); 383 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
388 if (insn & 0x2000) { 384 if (insn & 0x2000) {
@@ -392,10 +388,7 @@ int handle_popc(u32 insn, struct pt_regs *regs)
392 maybe_flush_windows(0, insn & 0x1f, rd, from_kernel); 388 maybe_flush_windows(0, insn & 0x1f, rd, from_kernel);
393 value = fetch_reg(insn & 0x1f, regs); 389 value = fetch_reg(insn & 0x1f, regs);
394 } 390 }
395 for (ret = 0, i = 0; i < 16; i++) { 391 ret = hweight64(value);
396 ret += popc_helper[value & 0xf];
397 value >>= 4;
398 }
399 if (rd < 16) { 392 if (rd < 16) {
400 if (rd) 393 if (rd)
401 regs->u_regs[rd] = ret; 394 regs->u_regs[rd] = ret;
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index c0220759003e..0e1605697b49 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -107,7 +107,26 @@ SECTIONS
107 *(.sun4v_2insn_patch) 107 *(.sun4v_2insn_patch)
108 __sun4v_2insn_patch_end = .; 108 __sun4v_2insn_patch_end = .;
109 } 109 }
110 110 .swapper_tsb_phys_patch : {
111 __swapper_tsb_phys_patch = .;
112 *(.swapper_tsb_phys_patch)
113 __swapper_tsb_phys_patch_end = .;
114 }
115 .swapper_4m_tsb_phys_patch : {
116 __swapper_4m_tsb_phys_patch = .;
117 *(.swapper_4m_tsb_phys_patch)
118 __swapper_4m_tsb_phys_patch_end = .;
119 }
120 .popc_3insn_patch : {
121 __popc_3insn_patch = .;
122 *(.popc_3insn_patch)
123 __popc_3insn_patch_end = .;
124 }
125 .popc_6insn_patch : {
126 __popc_6insn_patch = .;
127 *(.popc_6insn_patch)
128 __popc_6insn_patch_end = .;
129 }
111 PERCPU_SECTION(SMP_CACHE_BYTES) 130 PERCPU_SECTION(SMP_CACHE_BYTES)
112 131
113 . = ALIGN(PAGE_SIZE); 132 . = ALIGN(PAGE_SIZE);
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 7f01b8fce8bc..a3fc4375a150 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -31,13 +31,13 @@ lib-$(CONFIG_SPARC64) += NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o
31lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o 31lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o
32 32
33lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o 33lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o
34lib-$(CONFIG_SPARC64) += NG2patch.o NG2page.o 34lib-$(CONFIG_SPARC64) += NG2patch.o
35 35
36lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o 36lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
37lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o 37lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
38 38
39lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o 39lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
40lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o 40lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
41 41
42obj-y += iomap.o 42obj-y += iomap.o
43obj-$(CONFIG_SPARC32) += atomic32.o 43obj-$(CONFIG_SPARC32) += atomic32.o
diff --git a/arch/sparc/lib/NG2page.S b/arch/sparc/lib/NG2page.S
deleted file mode 100644
index 73b6b7c72cbf..000000000000
--- a/arch/sparc/lib/NG2page.S
+++ /dev/null
@@ -1,61 +0,0 @@
1/* NG2page.S: Niagara-2 optimized clear and copy page.
2 *
3 * Copyright (C) 2007 (davem@davemloft.net)
4 */
5
6#include <asm/asi.h>
7#include <asm/page.h>
8#include <asm/visasm.h>
9
10 .text
11 .align 32
12
13 /* This is heavily simplified from the sun4u variants
14 * because Niagara-2 does not have any D-cache aliasing issues.
15 */
16NG2copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
17 prefetch [%o1 + 0x00], #one_read
18 prefetch [%o1 + 0x40], #one_read
19 VISEntryHalf
20 set PAGE_SIZE, %g7
21 sub %o0, %o1, %g3
221: stxa %g0, [%o1 + %g3] ASI_BLK_INIT_QUAD_LDD_P
23 subcc %g7, 64, %g7
24 ldda [%o1] ASI_BLK_P, %f0
25 stda %f0, [%o1 + %g3] ASI_BLK_P
26 add %o1, 64, %o1
27 bne,pt %xcc, 1b
28 prefetch [%o1 + 0x40], #one_read
29 membar #Sync
30 VISExitHalf
31 retl
32 nop
33
34#define BRANCH_ALWAYS 0x10680000
35#define NOP 0x01000000
36#define NG_DO_PATCH(OLD, NEW) \
37 sethi %hi(NEW), %g1; \
38 or %g1, %lo(NEW), %g1; \
39 sethi %hi(OLD), %g2; \
40 or %g2, %lo(OLD), %g2; \
41 sub %g1, %g2, %g1; \
42 sethi %hi(BRANCH_ALWAYS), %g3; \
43 sll %g1, 11, %g1; \
44 srl %g1, 11 + 2, %g1; \
45 or %g3, %lo(BRANCH_ALWAYS), %g3; \
46 or %g3, %g1, %g3; \
47 stw %g3, [%g2]; \
48 sethi %hi(NOP), %g3; \
49 or %g3, %lo(NOP), %g3; \
50 stw %g3, [%g2 + 0x4]; \
51 flush %g2;
52
53 .globl niagara2_patch_pageops
54 .type niagara2_patch_pageops,#function
55niagara2_patch_pageops:
56 NG_DO_PATCH(copy_user_page, NG2copy_user_page)
57 NG_DO_PATCH(_clear_page, NGclear_page)
58 NG_DO_PATCH(clear_user_page, NGclear_user_page)
59 retl
60 nop
61 .size niagara2_patch_pageops,.-niagara2_patch_pageops
diff --git a/arch/sparc/lib/NGpage.S b/arch/sparc/lib/NGpage.S
index 428920de05ba..b9e790b9c6b8 100644
--- a/arch/sparc/lib/NGpage.S
+++ b/arch/sparc/lib/NGpage.S
@@ -16,55 +16,91 @@
16 */ 16 */
17 17
18NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ 18NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
19 prefetch [%o1 + 0x00], #one_read 19 save %sp, -192, %sp
20 mov 8, %g1 20 rd %asi, %g3
21 mov 16, %g2 21 wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
22 mov 24, %g3
23 set PAGE_SIZE, %g7 22 set PAGE_SIZE, %g7
23 prefetch [%i1 + 0x00], #one_read
24 prefetch [%i1 + 0x40], #one_read
24 25
251: ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2 261: prefetch [%i1 + 0x80], #one_read
26 ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4 27 prefetch [%i1 + 0xc0], #one_read
27 prefetch [%o1 + 0x40], #one_read 28 ldda [%i1 + 0x00] %asi, %o2
28 add %o1, 32, %o1 29 ldda [%i1 + 0x10] %asi, %o4
29 stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P 30 ldda [%i1 + 0x20] %asi, %l2
30 stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P 31 ldda [%i1 + 0x30] %asi, %l4
31 ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2 32 stxa %o2, [%i0 + 0x00] %asi
32 stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P 33 stxa %o3, [%i0 + 0x08] %asi
33 stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P 34 stxa %o4, [%i0 + 0x10] %asi
34 ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4 35 stxa %o5, [%i0 + 0x18] %asi
35 add %o1, 32, %o1 36 stxa %l2, [%i0 + 0x20] %asi
36 add %o0, 32, %o0 37 stxa %l3, [%i0 + 0x28] %asi
37 stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P 38 stxa %l4, [%i0 + 0x30] %asi
38 stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P 39 stxa %l5, [%i0 + 0x38] %asi
39 stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P 40 ldda [%i1 + 0x40] %asi, %o2
40 stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P 41 ldda [%i1 + 0x50] %asi, %o4
41 subcc %g7, 64, %g7 42 ldda [%i1 + 0x60] %asi, %l2
43 ldda [%i1 + 0x70] %asi, %l4
44 stxa %o2, [%i0 + 0x40] %asi
45 stxa %o3, [%i0 + 0x48] %asi
46 stxa %o4, [%i0 + 0x50] %asi
47 stxa %o5, [%i0 + 0x58] %asi
48 stxa %l2, [%i0 + 0x60] %asi
49 stxa %l3, [%i0 + 0x68] %asi
50 stxa %l4, [%i0 + 0x70] %asi
51 stxa %l5, [%i0 + 0x78] %asi
52 add %i1, 128, %i1
53 subcc %g7, 128, %g7
42 bne,pt %xcc, 1b 54 bne,pt %xcc, 1b
43 add %o0, 32, %o0 55 add %i0, 128, %i0
56 wr %g3, 0x0, %asi
44 membar #Sync 57 membar #Sync
45 retl 58 ret
46 nop 59 restore
47 60
48 .globl NGclear_page, NGclear_user_page 61 .align 32
49NGclear_page: /* %o0=dest */ 62NGclear_page: /* %o0=dest */
50NGclear_user_page: /* %o0=dest, %o1=vaddr */ 63NGclear_user_page: /* %o0=dest, %o1=vaddr */
51 mov 8, %g1 64 rd %asi, %g3
52 mov 16, %g2 65 wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
53 mov 24, %g3
54 set PAGE_SIZE, %g7 66 set PAGE_SIZE, %g7
55 67
561: stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P 681: stxa %g0, [%o0 + 0x00] %asi
57 stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P 69 stxa %g0, [%o0 + 0x08] %asi
58 stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P 70 stxa %g0, [%o0 + 0x10] %asi
59 stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P 71 stxa %g0, [%o0 + 0x18] %asi
60 add %o0, 32, %o0 72 stxa %g0, [%o0 + 0x20] %asi
61 stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P 73 stxa %g0, [%o0 + 0x28] %asi
62 stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P 74 stxa %g0, [%o0 + 0x30] %asi
63 stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P 75 stxa %g0, [%o0 + 0x38] %asi
64 stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P 76 stxa %g0, [%o0 + 0x40] %asi
65 subcc %g7, 64, %g7 77 stxa %g0, [%o0 + 0x48] %asi
78 stxa %g0, [%o0 + 0x50] %asi
79 stxa %g0, [%o0 + 0x58] %asi
80 stxa %g0, [%o0 + 0x60] %asi
81 stxa %g0, [%o0 + 0x68] %asi
82 stxa %g0, [%o0 + 0x70] %asi
83 stxa %g0, [%o0 + 0x78] %asi
84 stxa %g0, [%o0 + 0x80] %asi
85 stxa %g0, [%o0 + 0x88] %asi
86 stxa %g0, [%o0 + 0x90] %asi
87 stxa %g0, [%o0 + 0x98] %asi
88 stxa %g0, [%o0 + 0xa0] %asi
89 stxa %g0, [%o0 + 0xa8] %asi
90 stxa %g0, [%o0 + 0xb0] %asi
91 stxa %g0, [%o0 + 0xb8] %asi
92 stxa %g0, [%o0 + 0xc0] %asi
93 stxa %g0, [%o0 + 0xc8] %asi
94 stxa %g0, [%o0 + 0xd0] %asi
95 stxa %g0, [%o0 + 0xd8] %asi
96 stxa %g0, [%o0 + 0xe0] %asi
97 stxa %g0, [%o0 + 0xe8] %asi
98 stxa %g0, [%o0 + 0xf0] %asi
99 stxa %g0, [%o0 + 0xf8] %asi
100 subcc %g7, 256, %g7
66 bne,pt %xcc, 1b 101 bne,pt %xcc, 1b
67 add %o0, 32, %o0 102 add %o0, 256, %o0
103 wr %g3, 0x0, %asi
68 membar #Sync 104 membar #Sync
69 retl 105 retl
70 nop 106 nop
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index 8600eb2461b5..1d32b54089aa 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -65,7 +65,7 @@ int __atomic_add_unless(atomic_t *v, int a, int u)
65 if (ret != u) 65 if (ret != u)
66 v->counter += a; 66 v->counter += a;
67 spin_unlock_irqrestore(ATOMIC_HASH(v), flags); 67 spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
68 return ret != u; 68 return ret;
69} 69}
70EXPORT_SYMBOL(__atomic_add_unless); 70EXPORT_SYMBOL(__atomic_add_unless);
71 71
diff --git a/arch/sparc/lib/ffs.S b/arch/sparc/lib/ffs.S
new file mode 100644
index 000000000000..b39389f69899
--- /dev/null
+++ b/arch/sparc/lib/ffs.S
@@ -0,0 +1,84 @@
1#include <linux/linkage.h>
2
3 .register %g2,#scratch
4
5 .text
6 .align 32
7
8ENTRY(ffs)
9 brnz,pt %o0, 1f
10 mov 1, %o1
11 retl
12 clr %o0
13 nop
14 nop
15ENTRY(__ffs)
16 sllx %o0, 32, %g1 /* 1 */
17 srlx %o0, 32, %g2
18
19 clr %o1 /* 2 */
20 movrz %g1, %g2, %o0
21
22 movrz %g1, 32, %o1 /* 3 */
231: clr %o2
24
25 sllx %o0, (64 - 16), %g1 /* 4 */
26 srlx %o0, 16, %g2
27
28 movrz %g1, %g2, %o0 /* 5 */
29 clr %o3
30
31 movrz %g1, 16, %o2 /* 6 */
32 clr %o4
33
34 and %o0, 0xff, %g1 /* 7 */
35 srlx %o0, 8, %g2
36
37 movrz %g1, %g2, %o0 /* 8 */
38 clr %o5
39
40 movrz %g1, 8, %o3 /* 9 */
41 add %o2, %o1, %o2
42
43 and %o0, 0xf, %g1 /* 10 */
44 srlx %o0, 4, %g2
45
46 movrz %g1, %g2, %o0 /* 11 */
47 add %o2, %o3, %o2
48
49 movrz %g1, 4, %o4 /* 12 */
50
51 and %o0, 0x3, %g1 /* 13 */
52 srlx %o0, 2, %g2
53
54 movrz %g1, %g2, %o0 /* 14 */
55 add %o2, %o4, %o2
56
57 movrz %g1, 2, %o5 /* 15 */
58
59 and %o0, 0x1, %g1 /* 16 */
60
61 add %o2, %o5, %o2 /* 17 */
62 xor %g1, 0x1, %g1
63
64 retl /* 18 */
65 add %o2, %g1, %o0
66ENDPROC(ffs)
67ENDPROC(__ffs)
68
69 .section .popc_6insn_patch, "ax"
70 .word ffs
71 brz,pn %o0, 98f
72 neg %o0, %g1
73 xnor %o0, %g1, %o1
74 popc %o1, %o0
7598: retl
76 nop
77 .word __ffs
78 neg %o0, %g1
79 xnor %o0, %g1, %o1
80 popc %o1, %o0
81 retl
82 sub %o0, 1, %o0
83 nop
84 .previous
diff --git a/arch/sparc/lib/hweight.S b/arch/sparc/lib/hweight.S
new file mode 100644
index 000000000000..95414e0a6808
--- /dev/null
+++ b/arch/sparc/lib/hweight.S
@@ -0,0 +1,51 @@
1#include <linux/linkage.h>
2
3 .text
4 .align 32
5ENTRY(__arch_hweight8)
6 ba,pt %xcc, __sw_hweight8
7 nop
8 nop
9ENDPROC(__arch_hweight8)
10 .section .popc_3insn_patch, "ax"
11 .word __arch_hweight8
12 sllx %o0, 64-8, %g1
13 retl
14 popc %g1, %o0
15 .previous
16
17ENTRY(__arch_hweight16)
18 ba,pt %xcc, __sw_hweight16
19 nop
20 nop
21ENDPROC(__arch_hweight16)
22 .section .popc_3insn_patch, "ax"
23 .word __arch_hweight16
24 sllx %o0, 64-16, %g1
25 retl
26 popc %g1, %o0
27 .previous
28
29ENTRY(__arch_hweight32)
30 ba,pt %xcc, __sw_hweight32
31 nop
32 nop
33ENDPROC(__arch_hweight32)
34 .section .popc_3insn_patch, "ax"
35 .word __arch_hweight32
36 sllx %o0, 64-32, %g1
37 retl
38 popc %g1, %o0
39 .previous
40
41ENTRY(__arch_hweight64)
42 ba,pt %xcc, __sw_hweight64
43 nop
44 nop
45ENDPROC(__arch_hweight64)
46 .section .popc_3insn_patch, "ax"
47 .word __arch_hweight64
48 retl
49 popc %o0, %o0
50 nop
51 .previous
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 3fd8e18bed80..adfac23d976a 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -1597,6 +1597,42 @@ static void __init tsb_phys_patch(void)
1597static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR]; 1597static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];
1598extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES]; 1598extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
1599 1599
1600static void patch_one_ktsb_phys(unsigned int *start, unsigned int *end, unsigned long pa)
1601{
1602 pa >>= KTSB_PHYS_SHIFT;
1603
1604 while (start < end) {
1605 unsigned int *ia = (unsigned int *)(unsigned long)*start;
1606
1607 ia[0] = (ia[0] & ~0x3fffff) | (pa >> 10);
1608 __asm__ __volatile__("flush %0" : : "r" (ia));
1609
1610 ia[1] = (ia[1] & ~0x3ff) | (pa & 0x3ff);
1611 __asm__ __volatile__("flush %0" : : "r" (ia + 1));
1612
1613 start++;
1614 }
1615}
1616
1617static void ktsb_phys_patch(void)
1618{
1619 extern unsigned int __swapper_tsb_phys_patch;
1620 extern unsigned int __swapper_tsb_phys_patch_end;
1621 extern unsigned int __swapper_4m_tsb_phys_patch;
1622 extern unsigned int __swapper_4m_tsb_phys_patch_end;
1623 unsigned long ktsb_pa;
1624
1625 ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE);
1626 patch_one_ktsb_phys(&__swapper_tsb_phys_patch,
1627 &__swapper_tsb_phys_patch_end, ktsb_pa);
1628#ifndef CONFIG_DEBUG_PAGEALLOC
1629 ktsb_pa = (kern_base +
1630 ((unsigned long)&swapper_4m_tsb[0] - KERNBASE));
1631 patch_one_ktsb_phys(&__swapper_4m_tsb_phys_patch,
1632 &__swapper_4m_tsb_phys_patch_end, ktsb_pa);
1633#endif
1634}
1635
1600static void __init sun4v_ktsb_init(void) 1636static void __init sun4v_ktsb_init(void)
1601{ 1637{
1602 unsigned long ktsb_pa; 1638 unsigned long ktsb_pa;
@@ -1716,8 +1752,10 @@ void __init paging_init(void)
1716 sun4u_pgprot_init(); 1752 sun4u_pgprot_init();
1717 1753
1718 if (tlb_type == cheetah_plus || 1754 if (tlb_type == cheetah_plus ||
1719 tlb_type == hypervisor) 1755 tlb_type == hypervisor) {
1720 tsb_phys_patch(); 1756 tsb_phys_patch();
1757 ktsb_phys_patch();
1758 }
1721 1759
1722 if (tlb_type == hypervisor) { 1760 if (tlb_type == hypervisor) {
1723 sun4v_patch_tlb_handlers(); 1761 sun4v_patch_tlb_handlers();