diff options
| -rw-r--r-- | arch/sparc/include/asm/elf_64.h | 65 | ||||
| -rw-r--r-- | arch/sparc/kernel/cpu.c | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/kernel.h | 6 | ||||
| -rw-r--r-- | arch/sparc/kernel/setup_64.c | 149 |
4 files changed, 185 insertions, 36 deletions
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 | 183 | extern 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. */ | ||
| 170 | static 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/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/kernel.h b/arch/sparc/kernel/kernel.h index 6f6544cfa0ef..8325d7759381 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h | |||
| @@ -10,6 +10,12 @@ extern const char *sparc_pmu_type; | |||
| 10 | extern unsigned int fsr_storage; | 10 | extern unsigned int fsr_storage; |
| 11 | extern int ncpus_probed; | 11 | extern int ncpus_probed; |
| 12 | 12 | ||
| 13 | #ifdef CONFIG_SPARC64 | ||
| 14 | /* setup_64.c */ | ||
| 15 | struct seq_file; | ||
| 16 | extern void cpucap_info(struct seq_file *); | ||
| 17 | #endif | ||
| 18 | |||
| 13 | #ifdef CONFIG_SPARC32 | 19 | #ifdef CONFIG_SPARC32 |
| 14 | /* cpu.c */ | 20 | /* cpu.c */ |
| 15 | extern void cpu_probe(void); | 21 | extern void cpu_probe(void); |
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index c4dd0999da86..242dbb3f31d2 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> |
| @@ -278,6 +281,151 @@ void __init boot_cpu_id_too_large(int cpu) | |||
| 278 | } | 281 | } |
| 279 | #endif | 282 | #endif |
| 280 | 283 | ||
| 284 | /* On Ultra, we support all of the v8 capabilities. */ | ||
| 285 | unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | | ||
| 286 | HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | | ||
| 287 | HWCAP_SPARC_V9); | ||
| 288 | EXPORT_SYMBOL(sparc64_elf_hwcap); | ||
| 289 | |||
| 290 | static const char *hwcaps[] = { | ||
| 291 | "flush", "stbar", "swap", "muldiv", "v9", | ||
| 292 | "ultra3", "blkinit", "n2", | ||
| 293 | |||
| 294 | /* These strings are as they appear in the machine description | ||
| 295 | * 'hwcap-list' property for cpu nodes. | ||
| 296 | */ | ||
| 297 | "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2", | ||
| 298 | "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau", | ||
| 299 | "ima", "cspare", | ||
| 300 | }; | ||
| 301 | |||
| 302 | void cpucap_info(struct seq_file *m) | ||
| 303 | { | ||
| 304 | unsigned long caps = sparc64_elf_hwcap; | ||
| 305 | int i, printed = 0; | ||
| 306 | |||
| 307 | seq_puts(m, "cpucaps\t\t: "); | ||
| 308 | for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { | ||
| 309 | unsigned long bit = 1UL << i; | ||
| 310 | if (caps & bit) { | ||
| 311 | seq_printf(m, "%s%s", | ||
| 312 | printed ? "," : "", hwcaps[i]); | ||
| 313 | printed++; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | seq_putc(m, '\n'); | ||
| 317 | } | ||
| 318 | |||
| 319 | static void __init report_hwcaps(unsigned long caps) | ||
| 320 | { | ||
| 321 | int i, printed = 0; | ||
| 322 | |||
| 323 | printk(KERN_INFO "CPU CAPS: ["); | ||
| 324 | for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { | ||
| 325 | unsigned long bit = 1UL << i; | ||
| 326 | if (caps & bit) { | ||
| 327 | printk(KERN_CONT "%s%s", | ||
| 328 | printed ? "," : "", hwcaps[i]); | ||
| 329 | if (++printed == 8) { | ||
| 330 | printk(KERN_CONT "]\n"); | ||
| 331 | printk(KERN_INFO "CPU CAPS: ["); | ||
| 332 | printed = 0; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 336 | printk(KERN_CONT "]\n"); | ||
| 337 | } | ||
| 338 | |||
| 339 | static unsigned long __init mdesc_cpu_hwcap_list(void) | ||
| 340 | { | ||
| 341 | struct mdesc_handle *hp; | ||
| 342 | unsigned long caps = 0; | ||
| 343 | const char *prop; | ||
| 344 | int len; | ||
| 345 | u64 pn; | ||
| 346 | |||
| 347 | hp = mdesc_grab(); | ||
| 348 | if (!hp) | ||
| 349 | return 0; | ||
| 350 | |||
| 351 | pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu"); | ||
| 352 | if (pn == MDESC_NODE_NULL) | ||
| 353 | goto out; | ||
| 354 | |||
| 355 | prop = mdesc_get_property(hp, pn, "hwcap-list", &len); | ||
| 356 | if (!prop) | ||
| 357 | goto out; | ||
| 358 | |||
| 359 | while (len) { | ||
| 360 | int i, plen; | ||
| 361 | |||
| 362 | for (i = 0; i < ARRAY_SIZE(hwcaps); i++) { | ||
| 363 | unsigned long bit = 1UL << i; | ||
| 364 | |||
| 365 | if (!strcmp(prop, hwcaps[i])) { | ||
| 366 | caps |= bit; | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | plen = strlen(prop) + 1; | ||
| 372 | prop += plen; | ||
| 373 | len -= plen; | ||
| 374 | } | ||
| 375 | |||
| 376 | out: | ||
| 377 | mdesc_release(hp); | ||
| 378 | return caps; | ||
| 379 | } | ||
| 380 | |||
| 381 | /* This yields a mask that user programs can use to figure out what | ||
| 382 | * instruction set this cpu supports. | ||
| 383 | */ | ||
| 384 | static void __init init_sparc64_elf_hwcap(void) | ||
| 385 | { | ||
| 386 | unsigned long cap = sparc64_elf_hwcap; | ||
| 387 | unsigned long mdesc_caps; | ||
| 388 | |||
| 389 | if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 390 | cap |= HWCAP_SPARC_ULTRA3; | ||
| 391 | else if (tlb_type == hypervisor) { | ||
| 392 | if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || | ||
| 393 | sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || | ||
| 394 | sun4v_chip_type == SUN4V_CHIP_NIAGARA3) | ||
| 395 | cap |= HWCAP_SPARC_BLKINIT; | ||
| 396 | if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || | ||
| 397 | sun4v_chip_type == SUN4V_CHIP_NIAGARA3) | ||
| 398 | cap |= HWCAP_SPARC_N2; | ||
| 399 | } | ||
| 400 | |||
| 401 | cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS); | ||
| 402 | |||
| 403 | mdesc_caps = mdesc_cpu_hwcap_list(); | ||
| 404 | if (!mdesc_caps) { | ||
| 405 | if (tlb_type == spitfire) | ||
| 406 | cap |= AV_SPARC_VIS; | ||
| 407 | if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
| 408 | cap |= AV_SPARC_VIS | AV_SPARC_VIS2; | ||
| 409 | if (tlb_type == cheetah_plus) | ||
| 410 | cap |= AV_SPARC_POPC; | ||
| 411 | if (tlb_type == hypervisor) { | ||
| 412 | if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1) | ||
| 413 | cap |= AV_SPARC_ASI_BLK_INIT; | ||
| 414 | if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || | ||
| 415 | sun4v_chip_type == SUN4V_CHIP_NIAGARA3) | ||
| 416 | cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 | | ||
| 417 | AV_SPARC_ASI_BLK_INIT | | ||
| 418 | AV_SPARC_POPC); | ||
| 419 | if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3) | ||
| 420 | cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC | | ||
| 421 | AV_SPARC_FMAF); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | sparc64_elf_hwcap = cap | mdesc_caps; | ||
| 425 | |||
| 426 | report_hwcaps(sparc64_elf_hwcap); | ||
| 427 | } | ||
| 428 | |||
| 281 | void __init setup_arch(char **cmdline_p) | 429 | void __init setup_arch(char **cmdline_p) |
| 282 | { | 430 | { |
| 283 | /* Initialize PROM console and command line. */ | 431 | /* Initialize PROM console and command line. */ |
| @@ -337,6 +485,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 337 | init_cur_cpu_trap(current_thread_info()); | 485 | init_cur_cpu_trap(current_thread_info()); |
| 338 | 486 | ||
| 339 | paging_init(); | 487 | paging_init(); |
| 488 | init_sparc64_elf_hwcap(); | ||
| 340 | } | 489 | } |
| 341 | 490 | ||
| 342 | extern int stop_a_enabled; | 491 | extern int stop_a_enabled; |
