diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kernel/setup.c | 109 |
1 files changed, 109 insertions, 0 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) |