diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-05-04 12:48:28 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-05-04 12:48:35 -0400 |
commit | cf8ba7a95511b86608acb481ad96219fe2da4b3a (patch) | |
tree | f2a4fcba2c7ad7f29500eaaadc4a8488d8855cdd | |
parent | e29630627702571eb2b2a0955605b7f8971c82c1 (diff) |
[S390] add hardware capability support (ELF_HWCAP).
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/kernel/setup.c | 109 | ||||
-rw-r--r-- | include/asm-s390/elf.h | 7 | ||||
-rw-r--r-- | include/asm-s390/lowcore.h | 10 |
3 files changed, 120 insertions, 6 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 82b7fe32d86c..6bfb0889eb10 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -74,6 +74,8 @@ unsigned int console_mode = 0; | |||
74 | unsigned int console_devno = -1; | 74 | unsigned int console_devno = -1; |
75 | unsigned int console_irq = -1; | 75 | unsigned int console_irq = -1; |
76 | unsigned long machine_flags = 0; | 76 | unsigned long machine_flags = 0; |
77 | unsigned long elf_hwcap = 0; | ||
78 | char elf_platform[ELF_PLATFORM_SIZE]; | ||
77 | 79 | ||
78 | struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; | 80 | struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; |
79 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ | 81 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ |
@@ -749,6 +751,98 @@ setup_memory(void) | |||
749 | #endif | 751 | #endif |
750 | } | 752 | } |
751 | 753 | ||
754 | static __init unsigned int stfl(void) | ||
755 | { | ||
756 | asm volatile( | ||
757 | " .insn s,0xb2b10000,0(0)\n" /* stfl */ | ||
758 | "0:\n" | ||
759 | EX_TABLE(0b,0b)); | ||
760 | return S390_lowcore.stfl_fac_list; | ||
761 | } | ||
762 | |||
763 | static __init int stfle(unsigned long long *list, int doublewords) | ||
764 | { | ||
765 | typedef struct { unsigned long long _[doublewords]; } addrtype; | ||
766 | register unsigned long __nr asm("0") = doublewords - 1; | ||
767 | |||
768 | asm volatile(".insn s,0xb2b00000,%0" /* stfle */ | ||
769 | : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc"); | ||
770 | return __nr + 1; | ||
771 | } | ||
772 | |||
773 | /* | ||
774 | * Setup hardware capabilities. | ||
775 | */ | ||
776 | static void __init setup_hwcaps(void) | ||
777 | { | ||
778 | static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; | ||
779 | struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; | ||
780 | unsigned long long facility_list_extended; | ||
781 | unsigned int facility_list; | ||
782 | int i; | ||
783 | |||
784 | facility_list = stfl(); | ||
785 | /* | ||
786 | * The store facility list bits numbers as found in the principles | ||
787 | * of operation are numbered with bit 1UL<<31 as number 0 to | ||
788 | * bit 1UL<<0 as number 31. | ||
789 | * Bit 0: instructions named N3, "backported" to esa-mode | ||
790 | * Bit 2: z/Architecture mode is active | ||
791 | * Bit 7: the store-facility-list-extended facility is installed | ||
792 | * Bit 17: the message-security assist is installed | ||
793 | * Bit 19: the long-displacement facility is installed | ||
794 | * Bit 21: the extended-immediate facility is installed | ||
795 | * These get translated to: | ||
796 | * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1, | ||
797 | * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3, | ||
798 | * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5. | ||
799 | */ | ||
800 | for (i = 0; i < 6; i++) | ||
801 | if (facility_list & (1UL << (31 - stfl_bits[i]))) | ||
802 | elf_hwcap |= 1UL << i; | ||
803 | |||
804 | /* | ||
805 | * Check for additional facilities with store-facility-list-extended. | ||
806 | * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0 | ||
807 | * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information | ||
808 | * as stored by stfl, bits 32-xxx contain additional facilities. | ||
809 | * How many facility words are stored depends on the number of | ||
810 | * doublewords passed to the instruction. The additional facilites | ||
811 | * are: | ||
812 | * Bit 43: decimal floating point facility is installed | ||
813 | * translated to: | ||
814 | * HWCAP_S390_DFP bit 6. | ||
815 | */ | ||
816 | if ((elf_hwcap & (1UL << 2)) && | ||
817 | stfle(&facility_list_extended, 1) > 0) { | ||
818 | if (facility_list_extended & (1ULL << (64 - 43))) | ||
819 | elf_hwcap |= 1UL << 6; | ||
820 | } | ||
821 | |||
822 | switch (cpuinfo->cpu_id.machine) { | ||
823 | case 0x9672: | ||
824 | #if !defined(CONFIG_64BIT) | ||
825 | default: /* Use "g5" as default for 31 bit kernels. */ | ||
826 | #endif | ||
827 | strcpy(elf_platform, "g5"); | ||
828 | break; | ||
829 | case 0x2064: | ||
830 | case 0x2066: | ||
831 | #if defined(CONFIG_64BIT) | ||
832 | default: /* Use "z900" as default for 64 bit kernels. */ | ||
833 | #endif | ||
834 | strcpy(elf_platform, "z900"); | ||
835 | break; | ||
836 | case 0x2084: | ||
837 | case 0x2086: | ||
838 | strcpy(elf_platform, "z990"); | ||
839 | break; | ||
840 | case 0x2094: | ||
841 | strcpy(elf_platform, "z9-109"); | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | |||
752 | /* | 846 | /* |
753 | * Setup function called from init/main.c just after the banner | 847 | * Setup function called from init/main.c just after the banner |
754 | * was printed. | 848 | * was printed. |
@@ -805,6 +899,11 @@ setup_arch(char **cmdline_p) | |||
805 | smp_setup_cpu_possible_map(); | 899 | smp_setup_cpu_possible_map(); |
806 | 900 | ||
807 | /* | 901 | /* |
902 | * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). | ||
903 | */ | ||
904 | setup_hwcaps(); | ||
905 | |||
906 | /* | ||
808 | * Create kernel page tables and switch to virtual addressing. | 907 | * Create kernel page tables and switch to virtual addressing. |
809 | */ | 908 | */ |
810 | paging_init(); | 909 | paging_init(); |
@@ -839,8 +938,12 @@ void print_cpu_info(struct cpuinfo_S390 *cpuinfo) | |||
839 | 938 | ||
840 | static int show_cpuinfo(struct seq_file *m, void *v) | 939 | static int show_cpuinfo(struct seq_file *m, void *v) |
841 | { | 940 | { |
941 | static const char *hwcap_str[7] = { | ||
942 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp" | ||
943 | }; | ||
842 | struct cpuinfo_S390 *cpuinfo; | 944 | struct cpuinfo_S390 *cpuinfo; |
843 | unsigned long n = (unsigned long) v - 1; | 945 | unsigned long n = (unsigned long) v - 1; |
946 | int i; | ||
844 | 947 | ||
845 | s390_adjust_jiffies(); | 948 | s390_adjust_jiffies(); |
846 | preempt_disable(); | 949 | preempt_disable(); |
@@ -850,7 +953,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
850 | "bogomips per cpu: %lu.%02lu\n", | 953 | "bogomips per cpu: %lu.%02lu\n", |
851 | num_online_cpus(), loops_per_jiffy/(500000/HZ), | 954 | num_online_cpus(), loops_per_jiffy/(500000/HZ), |
852 | (loops_per_jiffy/(5000/HZ))%100); | 955 | (loops_per_jiffy/(5000/HZ))%100); |
956 | seq_puts(m, "features\t: "); | ||
957 | for (i = 0; i < 7; i++) | ||
958 | if (hwcap_str[i] && (elf_hwcap & (1UL << i))) | ||
959 | seq_printf(m, "%s ", hwcap_str[i]); | ||
960 | seq_puts(m, "\n"); | ||
853 | } | 961 | } |
962 | |||
854 | if (cpu_online(n)) { | 963 | if (cpu_online(n)) { |
855 | #ifdef CONFIG_SMP | 964 | #ifdef CONFIG_SMP |
856 | if (smp_processor_id() == n) | 965 | if (smp_processor_id() == n) |
diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index c0d629d61d3e..91d06325cc79 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h | |||
@@ -188,7 +188,8 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) | |||
188 | /* This yields a mask that user programs can use to figure out what | 188 | /* This yields a mask that user programs can use to figure out what |
189 | instruction set this CPU supports. */ | 189 | instruction set this CPU supports. */ |
190 | 190 | ||
191 | #define ELF_HWCAP (0) | 191 | extern unsigned long elf_hwcap; |
192 | #define ELF_HWCAP (elf_hwcap) | ||
192 | 193 | ||
193 | /* This yields a string that ld.so will use to load implementation | 194 | /* This yields a string that ld.so will use to load implementation |
194 | specific libraries for optimization. This is more specific in | 195 | specific libraries for optimization. This is more specific in |
@@ -197,7 +198,9 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) | |||
197 | For the moment, we have only optimizations for the Intel generations, | 198 | For the moment, we have only optimizations for the Intel generations, |
198 | but that could change... */ | 199 | but that could change... */ |
199 | 200 | ||
200 | #define ELF_PLATFORM (NULL) | 201 | #define ELF_PLATFORM_SIZE 8 |
202 | extern char elf_platform[]; | ||
203 | #define ELF_PLATFORM (elf_platform) | ||
201 | 204 | ||
202 | #ifndef __s390x__ | 205 | #ifndef __s390x__ |
203 | #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) | 206 | #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) |
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index ffc9788a21a7..801a6fd35b5b 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h | |||
@@ -229,17 +229,19 @@ struct _lowcore | |||
229 | __u16 subchannel_nr; /* 0x0ba */ | 229 | __u16 subchannel_nr; /* 0x0ba */ |
230 | __u32 io_int_parm; /* 0x0bc */ | 230 | __u32 io_int_parm; /* 0x0bc */ |
231 | __u32 io_int_word; /* 0x0c0 */ | 231 | __u32 io_int_word; /* 0x0c0 */ |
232 | __u8 pad3[0xD4-0xC4]; /* 0x0c4 */ | 232 | __u8 pad3[0xc8-0xc4]; /* 0x0c4 */ |
233 | __u32 stfl_fac_list; /* 0x0c8 */ | ||
234 | __u8 pad4[0xd4-0xcc]; /* 0x0cc */ | ||
233 | __u32 extended_save_area_addr; /* 0x0d4 */ | 235 | __u32 extended_save_area_addr; /* 0x0d4 */ |
234 | __u32 cpu_timer_save_area[2]; /* 0x0d8 */ | 236 | __u32 cpu_timer_save_area[2]; /* 0x0d8 */ |
235 | __u32 clock_comp_save_area[2]; /* 0x0e0 */ | 237 | __u32 clock_comp_save_area[2]; /* 0x0e0 */ |
236 | __u32 mcck_interruption_code[2]; /* 0x0e8 */ | 238 | __u32 mcck_interruption_code[2]; /* 0x0e8 */ |
237 | __u8 pad4[0xf4-0xf0]; /* 0x0f0 */ | 239 | __u8 pad5[0xf4-0xf0]; /* 0x0f0 */ |
238 | __u32 external_damage_code; /* 0x0f4 */ | 240 | __u32 external_damage_code; /* 0x0f4 */ |
239 | __u32 failing_storage_address; /* 0x0f8 */ | 241 | __u32 failing_storage_address; /* 0x0f8 */ |
240 | __u8 pad5[0x100-0xfc]; /* 0x0fc */ | 242 | __u8 pad6[0x100-0xfc]; /* 0x0fc */ |
241 | __u32 st_status_fixed_logout[4];/* 0x100 */ | 243 | __u32 st_status_fixed_logout[4];/* 0x100 */ |
242 | __u8 pad6[0x120-0x110]; /* 0x110 */ | 244 | __u8 pad7[0x120-0x110]; /* 0x110 */ |
243 | __u32 access_regs_save_area[16];/* 0x120 */ | 245 | __u32 access_regs_save_area[16];/* 0x120 */ |
244 | __u32 floating_pt_save_area[8]; /* 0x160 */ | 246 | __u32 floating_pt_save_area[8]; /* 0x160 */ |
245 | __u32 gpregs_save_area[16]; /* 0x180 */ | 247 | __u32 gpregs_save_area[16]; /* 0x180 */ |