aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
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/kernel
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/kernel')
-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
14 files changed, 330 insertions, 41 deletions
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);