Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/HWCAP: Use system wide safe values

Extend struct arm64_cpu_capabilities to handle the HWCAP detection
and make use of the system wide value of the feature registers for
a reliable set of HWCAPs.

Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Tested-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Suzuki K. Poulose and committed by
Catalin Marinas
37b01d53 da8d02d1

+101 -72
+2
arch/arm64/include/asm/cpufeature.h
··· 81 81 u32 sys_reg; 82 82 int field_pos; 83 83 int min_field_value; 84 + int hwcap_type; 85 + unsigned long hwcap; 84 86 }; 85 87 }; 86 88 };
+8
arch/arm64/include/asm/hwcap.h
··· 52 52 extern unsigned int compat_elf_hwcap, compat_elf_hwcap2; 53 53 #endif 54 54 55 + enum { 56 + CAP_HWCAP = 1, 57 + #ifdef CONFIG_COMPAT 58 + CAP_COMPAT_HWCAP, 59 + CAP_COMPAT_HWCAP2, 60 + #endif 61 + }; 62 + 55 63 extern unsigned long elf_hwcap; 56 64 #endif 57 65 #endif
+91 -72
arch/arm64/kernel/cpufeature.c
··· 628 628 {}, 629 629 }; 630 630 631 + #define HWCAP_CAP(reg, field, min_value, type, cap) \ 632 + { \ 633 + .desc = #cap, \ 634 + .matches = has_cpuid_feature, \ 635 + .sys_reg = reg, \ 636 + .field_pos = field, \ 637 + .min_field_value = min_value, \ 638 + .hwcap_type = type, \ 639 + .hwcap = cap, \ 640 + } 641 + 642 + static const struct arm64_cpu_capabilities arm64_hwcaps[] = { 643 + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, 2, CAP_HWCAP, HWCAP_PMULL), 644 + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, 1, CAP_HWCAP, HWCAP_AES), 645 + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, 1, CAP_HWCAP, HWCAP_SHA1), 646 + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, 1, CAP_HWCAP, HWCAP_SHA2), 647 + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, 1, CAP_HWCAP, HWCAP_CRC32), 648 + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, 2, CAP_HWCAP, HWCAP_ATOMICS), 649 + #ifdef CONFIG_COMPAT 650 + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL), 651 + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES), 652 + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1), 653 + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2), 654 + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32), 655 + #endif 656 + {}, 657 + }; 658 + 659 + static void cap_set_hwcap(const struct arm64_cpu_capabilities *cap) 660 + { 661 + switch (cap->hwcap_type) { 662 + case CAP_HWCAP: 663 + elf_hwcap |= cap->hwcap; 664 + break; 665 + #ifdef CONFIG_COMPAT 666 + case CAP_COMPAT_HWCAP: 667 + compat_elf_hwcap |= (u32)cap->hwcap; 668 + break; 669 + case CAP_COMPAT_HWCAP2: 670 + compat_elf_hwcap2 |= (u32)cap->hwcap; 671 + break; 672 + #endif 673 + default: 674 + WARN_ON(1); 675 + break; 676 + } 677 + } 678 + 679 + /* Check if we have a particular HWCAP enabled */ 680 + static bool cpus_have_hwcap(const struct arm64_cpu_capabilities *cap) 681 + { 682 + bool rc; 683 + 684 + switch (cap->hwcap_type) { 685 + case CAP_HWCAP: 686 + rc = (elf_hwcap & cap->hwcap) != 0; 687 + break; 688 + #ifdef CONFIG_COMPAT 689 + case CAP_COMPAT_HWCAP: 690 + rc = (compat_elf_hwcap & (u32)cap->hwcap) != 0; 691 + break; 692 + case CAP_COMPAT_HWCAP2: 693 + rc = (compat_elf_hwcap2 & (u32)cap->hwcap) != 0; 694 + break; 695 + #endif 696 + default: 697 + WARN_ON(1); 698 + rc = false; 699 + } 700 + 701 + return rc; 702 + } 703 + 704 + static void setup_cpu_hwcaps(void) 705 + { 706 + int i; 707 + const struct arm64_cpu_capabilities *hwcaps = arm64_hwcaps; 708 + 709 + for (i = 0; hwcaps[i].desc; i++) 710 + if (hwcaps[i].matches(&hwcaps[i])) 711 + cap_set_hwcap(&hwcaps[i]); 712 + } 713 + 631 714 void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, 632 715 const char *info) 633 716 { ··· 852 769 if (caps[i].enable) 853 770 caps[i].enable(NULL); 854 771 } 772 + 773 + for (i = 0, caps = arm64_hwcaps; caps[i].desc; i++) { 774 + if (!cpus_have_hwcap(&caps[i])) 775 + continue; 776 + if (!feature_matches(__raw_read_system_reg(caps[i].sys_reg), &caps[i])) 777 + fail_incapable_cpu("arm64_hwcaps", &caps[i]); 778 + } 855 779 } 856 780 857 781 #else /* !CONFIG_HOTPLUG_CPU */ ··· 877 787 878 788 void __init setup_cpu_features(void) 879 789 { 880 - u64 features; 881 - s64 block; 882 790 u32 cwg; 883 791 int cls; 884 792 885 793 /* Set the CPU feature capabilies */ 886 794 setup_feature_capabilities(); 795 + setup_cpu_hwcaps(); 887 796 888 797 /* Advertise that we have computed the system capabilities */ 889 798 set_sys_caps_initialised(); ··· 898 809 if (L1_CACHE_BYTES < cls) 899 810 pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n", 900 811 L1_CACHE_BYTES, cls); 901 - 902 - /* 903 - * ID_AA64ISAR0_EL1 contains 4-bit wide signed feature blocks. 904 - * The blocks we test below represent incremental functionality 905 - * for non-negative values. Negative values are reserved. 906 - */ 907 - features = read_cpuid(ID_AA64ISAR0_EL1); 908 - block = cpuid_feature_extract_field(features, 4); 909 - if (block > 0) { 910 - switch (block) { 911 - default: 912 - case 2: 913 - elf_hwcap |= HWCAP_PMULL; 914 - case 1: 915 - elf_hwcap |= HWCAP_AES; 916 - case 0: 917 - break; 918 - } 919 - } 920 - 921 - if (cpuid_feature_extract_field(features, 8) > 0) 922 - elf_hwcap |= HWCAP_SHA1; 923 - 924 - if (cpuid_feature_extract_field(features, 12) > 0) 925 - elf_hwcap |= HWCAP_SHA2; 926 - 927 - if (cpuid_feature_extract_field(features, 16) > 0) 928 - elf_hwcap |= HWCAP_CRC32; 929 - 930 - block = cpuid_feature_extract_field(features, 20); 931 - if (block > 0) { 932 - switch (block) { 933 - default: 934 - case 2: 935 - elf_hwcap |= HWCAP_ATOMICS; 936 - case 1: 937 - /* RESERVED */ 938 - case 0: 939 - break; 940 - } 941 - } 942 - 943 - #ifdef CONFIG_COMPAT 944 - /* 945 - * ID_ISAR5_EL1 carries similar information as above, but pertaining to 946 - * the AArch32 32-bit execution state. 947 - */ 948 - features = read_cpuid(ID_ISAR5_EL1); 949 - block = cpuid_feature_extract_field(features, 4); 950 - if (block > 0) { 951 - switch (block) { 952 - default: 953 - case 2: 954 - compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL; 955 - case 1: 956 - compat_elf_hwcap2 |= COMPAT_HWCAP2_AES; 957 - case 0: 958 - break; 959 - } 960 - } 961 - 962 - if (cpuid_feature_extract_field(features, 8) > 0) 963 - compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1; 964 - 965 - if (cpuid_feature_extract_field(features, 12) > 0) 966 - compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2; 967 - 968 - if (cpuid_feature_extract_field(features, 16) > 0) 969 - compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32; 970 - #endif 971 812 }