Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Record and handle CPU attributes.
0004  *
0005  * Copyright (C) 2014 ARM Ltd.
0006  */
0007 #include <asm/arch_timer.h>
0008 #include <asm/cache.h>
0009 #include <asm/cpu.h>
0010 #include <asm/cputype.h>
0011 #include <asm/cpufeature.h>
0012 #include <asm/fpsimd.h>
0013 
0014 #include <linux/bitops.h>
0015 #include <linux/bug.h>
0016 #include <linux/compat.h>
0017 #include <linux/elf.h>
0018 #include <linux/init.h>
0019 #include <linux/kernel.h>
0020 #include <linux/personality.h>
0021 #include <linux/preempt.h>
0022 #include <linux/printk.h>
0023 #include <linux/seq_file.h>
0024 #include <linux/sched.h>
0025 #include <linux/smp.h>
0026 #include <linux/delay.h>
0027 
0028 /*
0029  * In case the boot CPU is hotpluggable, we record its initial state and
0030  * current state separately. Certain system registers may contain different
0031  * values depending on configuration at or after reset.
0032  */
0033 DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
0034 static struct cpuinfo_arm64 boot_cpu_data;
0035 
0036 static inline const char *icache_policy_str(int l1ip)
0037 {
0038     switch (l1ip) {
0039     case CTR_EL0_L1Ip_VPIPT:
0040         return "VPIPT";
0041     case CTR_EL0_L1Ip_VIPT:
0042         return "VIPT";
0043     case CTR_EL0_L1Ip_PIPT:
0044         return "PIPT";
0045     default:
0046         return "RESERVED/UNKNOWN";
0047     }
0048 }
0049 
0050 unsigned long __icache_flags;
0051 
0052 static const char *const hwcap_str[] = {
0053     [KERNEL_HWCAP_FP]       = "fp",
0054     [KERNEL_HWCAP_ASIMD]        = "asimd",
0055     [KERNEL_HWCAP_EVTSTRM]      = "evtstrm",
0056     [KERNEL_HWCAP_AES]      = "aes",
0057     [KERNEL_HWCAP_PMULL]        = "pmull",
0058     [KERNEL_HWCAP_SHA1]     = "sha1",
0059     [KERNEL_HWCAP_SHA2]     = "sha2",
0060     [KERNEL_HWCAP_CRC32]        = "crc32",
0061     [KERNEL_HWCAP_ATOMICS]      = "atomics",
0062     [KERNEL_HWCAP_FPHP]     = "fphp",
0063     [KERNEL_HWCAP_ASIMDHP]      = "asimdhp",
0064     [KERNEL_HWCAP_CPUID]        = "cpuid",
0065     [KERNEL_HWCAP_ASIMDRDM]     = "asimdrdm",
0066     [KERNEL_HWCAP_JSCVT]        = "jscvt",
0067     [KERNEL_HWCAP_FCMA]     = "fcma",
0068     [KERNEL_HWCAP_LRCPC]        = "lrcpc",
0069     [KERNEL_HWCAP_DCPOP]        = "dcpop",
0070     [KERNEL_HWCAP_SHA3]     = "sha3",
0071     [KERNEL_HWCAP_SM3]      = "sm3",
0072     [KERNEL_HWCAP_SM4]      = "sm4",
0073     [KERNEL_HWCAP_ASIMDDP]      = "asimddp",
0074     [KERNEL_HWCAP_SHA512]       = "sha512",
0075     [KERNEL_HWCAP_SVE]      = "sve",
0076     [KERNEL_HWCAP_ASIMDFHM]     = "asimdfhm",
0077     [KERNEL_HWCAP_DIT]      = "dit",
0078     [KERNEL_HWCAP_USCAT]        = "uscat",
0079     [KERNEL_HWCAP_ILRCPC]       = "ilrcpc",
0080     [KERNEL_HWCAP_FLAGM]        = "flagm",
0081     [KERNEL_HWCAP_SSBS]     = "ssbs",
0082     [KERNEL_HWCAP_SB]       = "sb",
0083     [KERNEL_HWCAP_PACA]     = "paca",
0084     [KERNEL_HWCAP_PACG]     = "pacg",
0085     [KERNEL_HWCAP_DCPODP]       = "dcpodp",
0086     [KERNEL_HWCAP_SVE2]     = "sve2",
0087     [KERNEL_HWCAP_SVEAES]       = "sveaes",
0088     [KERNEL_HWCAP_SVEPMULL]     = "svepmull",
0089     [KERNEL_HWCAP_SVEBITPERM]   = "svebitperm",
0090     [KERNEL_HWCAP_SVESHA3]      = "svesha3",
0091     [KERNEL_HWCAP_SVESM4]       = "svesm4",
0092     [KERNEL_HWCAP_FLAGM2]       = "flagm2",
0093     [KERNEL_HWCAP_FRINT]        = "frint",
0094     [KERNEL_HWCAP_SVEI8MM]      = "svei8mm",
0095     [KERNEL_HWCAP_SVEF32MM]     = "svef32mm",
0096     [KERNEL_HWCAP_SVEF64MM]     = "svef64mm",
0097     [KERNEL_HWCAP_SVEBF16]      = "svebf16",
0098     [KERNEL_HWCAP_I8MM]     = "i8mm",
0099     [KERNEL_HWCAP_BF16]     = "bf16",
0100     [KERNEL_HWCAP_DGH]      = "dgh",
0101     [KERNEL_HWCAP_RNG]      = "rng",
0102     [KERNEL_HWCAP_BTI]      = "bti",
0103     [KERNEL_HWCAP_MTE]      = "mte",
0104     [KERNEL_HWCAP_ECV]      = "ecv",
0105     [KERNEL_HWCAP_AFP]      = "afp",
0106     [KERNEL_HWCAP_RPRES]        = "rpres",
0107     [KERNEL_HWCAP_MTE3]     = "mte3",
0108     [KERNEL_HWCAP_SME]      = "sme",
0109     [KERNEL_HWCAP_SME_I16I64]   = "smei16i64",
0110     [KERNEL_HWCAP_SME_F64F64]   = "smef64f64",
0111     [KERNEL_HWCAP_SME_I8I32]    = "smei8i32",
0112     [KERNEL_HWCAP_SME_F16F32]   = "smef16f32",
0113     [KERNEL_HWCAP_SME_B16F32]   = "smeb16f32",
0114     [KERNEL_HWCAP_SME_F32F32]   = "smef32f32",
0115     [KERNEL_HWCAP_SME_FA64]     = "smefa64",
0116     [KERNEL_HWCAP_WFXT]     = "wfxt",
0117     [KERNEL_HWCAP_EBF16]        = "ebf16",
0118 };
0119 
0120 #ifdef CONFIG_COMPAT
0121 #define COMPAT_KERNEL_HWCAP(x)  const_ilog2(COMPAT_HWCAP_ ## x)
0122 static const char *const compat_hwcap_str[] = {
0123     [COMPAT_KERNEL_HWCAP(SWP)]  = "swp",
0124     [COMPAT_KERNEL_HWCAP(HALF)] = "half",
0125     [COMPAT_KERNEL_HWCAP(THUMB)]    = "thumb",
0126     [COMPAT_KERNEL_HWCAP(26BIT)]    = NULL, /* Not possible on arm64 */
0127     [COMPAT_KERNEL_HWCAP(FAST_MULT)] = "fastmult",
0128     [COMPAT_KERNEL_HWCAP(FPA)]  = NULL, /* Not possible on arm64 */
0129     [COMPAT_KERNEL_HWCAP(VFP)]  = "vfp",
0130     [COMPAT_KERNEL_HWCAP(EDSP)] = "edsp",
0131     [COMPAT_KERNEL_HWCAP(JAVA)] = NULL, /* Not possible on arm64 */
0132     [COMPAT_KERNEL_HWCAP(IWMMXT)]   = NULL, /* Not possible on arm64 */
0133     [COMPAT_KERNEL_HWCAP(CRUNCH)]   = NULL, /* Not possible on arm64 */
0134     [COMPAT_KERNEL_HWCAP(THUMBEE)]  = NULL, /* Not possible on arm64 */
0135     [COMPAT_KERNEL_HWCAP(NEON)] = "neon",
0136     [COMPAT_KERNEL_HWCAP(VFPv3)]    = "vfpv3",
0137     [COMPAT_KERNEL_HWCAP(VFPV3D16)] = NULL, /* Not possible on arm64 */
0138     [COMPAT_KERNEL_HWCAP(TLS)]  = "tls",
0139     [COMPAT_KERNEL_HWCAP(VFPv4)]    = "vfpv4",
0140     [COMPAT_KERNEL_HWCAP(IDIVA)]    = "idiva",
0141     [COMPAT_KERNEL_HWCAP(IDIVT)]    = "idivt",
0142     [COMPAT_KERNEL_HWCAP(VFPD32)]   = NULL, /* Not possible on arm64 */
0143     [COMPAT_KERNEL_HWCAP(LPAE)] = "lpae",
0144     [COMPAT_KERNEL_HWCAP(EVTSTRM)]  = "evtstrm",
0145 };
0146 
0147 #define COMPAT_KERNEL_HWCAP2(x) const_ilog2(COMPAT_HWCAP2_ ## x)
0148 static const char *const compat_hwcap2_str[] = {
0149     [COMPAT_KERNEL_HWCAP2(AES)] = "aes",
0150     [COMPAT_KERNEL_HWCAP2(PMULL)]   = "pmull",
0151     [COMPAT_KERNEL_HWCAP2(SHA1)]    = "sha1",
0152     [COMPAT_KERNEL_HWCAP2(SHA2)]    = "sha2",
0153     [COMPAT_KERNEL_HWCAP2(CRC32)]   = "crc32",
0154 };
0155 #endif /* CONFIG_COMPAT */
0156 
0157 static int c_show(struct seq_file *m, void *v)
0158 {
0159     int i, j;
0160     bool compat = personality(current->personality) == PER_LINUX32;
0161 
0162     for_each_online_cpu(i) {
0163         struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
0164         u32 midr = cpuinfo->reg_midr;
0165 
0166         /*
0167          * glibc reads /proc/cpuinfo to determine the number of
0168          * online processors, looking for lines beginning with
0169          * "processor".  Give glibc what it expects.
0170          */
0171         seq_printf(m, "processor\t: %d\n", i);
0172         if (compat)
0173             seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
0174                    MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
0175 
0176         seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
0177                loops_per_jiffy / (500000UL/HZ),
0178                loops_per_jiffy / (5000UL/HZ) % 100);
0179 
0180         /*
0181          * Dump out the common processor features in a single line.
0182          * Userspace should read the hwcaps with getauxval(AT_HWCAP)
0183          * rather than attempting to parse this, but there's a body of
0184          * software which does already (at least for 32-bit).
0185          */
0186         seq_puts(m, "Features\t:");
0187         if (compat) {
0188 #ifdef CONFIG_COMPAT
0189             for (j = 0; j < ARRAY_SIZE(compat_hwcap_str); j++) {
0190                 if (compat_elf_hwcap & (1 << j)) {
0191                     /*
0192                      * Warn once if any feature should not
0193                      * have been present on arm64 platform.
0194                      */
0195                     if (WARN_ON_ONCE(!compat_hwcap_str[j]))
0196                         continue;
0197 
0198                     seq_printf(m, " %s", compat_hwcap_str[j]);
0199                 }
0200             }
0201 
0202             for (j = 0; j < ARRAY_SIZE(compat_hwcap2_str); j++)
0203                 if (compat_elf_hwcap2 & (1 << j))
0204                     seq_printf(m, " %s", compat_hwcap2_str[j]);
0205 #endif /* CONFIG_COMPAT */
0206         } else {
0207             for (j = 0; j < ARRAY_SIZE(hwcap_str); j++)
0208                 if (cpu_have_feature(j))
0209                     seq_printf(m, " %s", hwcap_str[j]);
0210         }
0211         seq_puts(m, "\n");
0212 
0213         seq_printf(m, "CPU implementer\t: 0x%02x\n",
0214                MIDR_IMPLEMENTOR(midr));
0215         seq_printf(m, "CPU architecture: 8\n");
0216         seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
0217         seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
0218         seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
0219     }
0220 
0221     return 0;
0222 }
0223 
0224 static void *c_start(struct seq_file *m, loff_t *pos)
0225 {
0226     return *pos < 1 ? (void *)1 : NULL;
0227 }
0228 
0229 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
0230 {
0231     ++*pos;
0232     return NULL;
0233 }
0234 
0235 static void c_stop(struct seq_file *m, void *v)
0236 {
0237 }
0238 
0239 const struct seq_operations cpuinfo_op = {
0240     .start  = c_start,
0241     .next   = c_next,
0242     .stop   = c_stop,
0243     .show   = c_show
0244 };
0245 
0246 
0247 static struct kobj_type cpuregs_kobj_type = {
0248     .sysfs_ops = &kobj_sysfs_ops,
0249 };
0250 
0251 /*
0252  * The ARM ARM uses the phrase "32-bit register" to describe a register
0253  * whose upper 32 bits are RES0 (per C5.1.1, ARM DDI 0487A.i), however
0254  * no statement is made as to whether the upper 32 bits will or will not
0255  * be made use of in future, and between ARM DDI 0487A.c and ARM DDI
0256  * 0487A.d CLIDR_EL1 was expanded from 32-bit to 64-bit.
0257  *
0258  * Thus, while both MIDR_EL1 and REVIDR_EL1 are described as 32-bit
0259  * registers, we expose them both as 64 bit values to cater for possible
0260  * future expansion without an ABI break.
0261  */
0262 #define kobj_to_cpuinfo(kobj)   container_of(kobj, struct cpuinfo_arm64, kobj)
0263 #define CPUREGS_ATTR_RO(_name, _field)                      \
0264     static ssize_t _name##_show(struct kobject *kobj,           \
0265             struct kobj_attribute *attr, char *buf)         \
0266     {                                   \
0267         struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj);     \
0268                                         \
0269         if (info->reg_midr)                     \
0270             return sprintf(buf, "0x%016llx\n", info->reg_##_field); \
0271         else                                \
0272             return 0;                       \
0273     }                                   \
0274     static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RO(_name)
0275 
0276 CPUREGS_ATTR_RO(midr_el1, midr);
0277 CPUREGS_ATTR_RO(revidr_el1, revidr);
0278 CPUREGS_ATTR_RO(smidr_el1, smidr);
0279 
0280 static struct attribute *cpuregs_id_attrs[] = {
0281     &cpuregs_attr_midr_el1.attr,
0282     &cpuregs_attr_revidr_el1.attr,
0283     NULL
0284 };
0285 
0286 static const struct attribute_group cpuregs_attr_group = {
0287     .attrs = cpuregs_id_attrs,
0288     .name = "identification"
0289 };
0290 
0291 static struct attribute *sme_cpuregs_id_attrs[] = {
0292     &cpuregs_attr_smidr_el1.attr,
0293     NULL
0294 };
0295 
0296 static const struct attribute_group sme_cpuregs_attr_group = {
0297     .attrs = sme_cpuregs_id_attrs,
0298     .name = "identification"
0299 };
0300 
0301 static int cpuid_cpu_online(unsigned int cpu)
0302 {
0303     int rc;
0304     struct device *dev;
0305     struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
0306 
0307     dev = get_cpu_device(cpu);
0308     if (!dev) {
0309         rc = -ENODEV;
0310         goto out;
0311     }
0312     rc = kobject_add(&info->kobj, &dev->kobj, "regs");
0313     if (rc)
0314         goto out;
0315     rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group);
0316     if (rc)
0317         kobject_del(&info->kobj);
0318     if (system_supports_sme())
0319         rc = sysfs_merge_group(&info->kobj, &sme_cpuregs_attr_group);
0320 out:
0321     return rc;
0322 }
0323 
0324 static int cpuid_cpu_offline(unsigned int cpu)
0325 {
0326     struct device *dev;
0327     struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
0328 
0329     dev = get_cpu_device(cpu);
0330     if (!dev)
0331         return -ENODEV;
0332     if (info->kobj.parent) {
0333         sysfs_remove_group(&info->kobj, &cpuregs_attr_group);
0334         kobject_del(&info->kobj);
0335     }
0336 
0337     return 0;
0338 }
0339 
0340 static int __init cpuinfo_regs_init(void)
0341 {
0342     int cpu, ret;
0343 
0344     for_each_possible_cpu(cpu) {
0345         struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
0346 
0347         kobject_init(&info->kobj, &cpuregs_kobj_type);
0348     }
0349 
0350     ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/cpuinfo:online",
0351                 cpuid_cpu_online, cpuid_cpu_offline);
0352     if (ret < 0) {
0353         pr_err("cpuinfo: failed to register hotplug callbacks.\n");
0354         return ret;
0355     }
0356     return 0;
0357 }
0358 device_initcall(cpuinfo_regs_init);
0359 
0360 static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
0361 {
0362     unsigned int cpu = smp_processor_id();
0363     u32 l1ip = CTR_L1IP(info->reg_ctr);
0364 
0365     switch (l1ip) {
0366     case CTR_EL0_L1Ip_PIPT:
0367         break;
0368     case CTR_EL0_L1Ip_VPIPT:
0369         set_bit(ICACHEF_VPIPT, &__icache_flags);
0370         break;
0371     case CTR_EL0_L1Ip_VIPT:
0372     default:
0373         /* Assume aliasing */
0374         set_bit(ICACHEF_ALIASING, &__icache_flags);
0375         break;
0376     }
0377 
0378     pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str(l1ip), cpu);
0379 }
0380 
0381 static void __cpuinfo_store_cpu_32bit(struct cpuinfo_32bit *info)
0382 {
0383     info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
0384     info->reg_id_dfr1 = read_cpuid(ID_DFR1_EL1);
0385     info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
0386     info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
0387     info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
0388     info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
0389     info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
0390     info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
0391     info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1);
0392     info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
0393     info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
0394     info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
0395     info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
0396     info->reg_id_mmfr4 = read_cpuid(ID_MMFR4_EL1);
0397     info->reg_id_mmfr5 = read_cpuid(ID_MMFR5_EL1);
0398     info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
0399     info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
0400     info->reg_id_pfr2 = read_cpuid(ID_PFR2_EL1);
0401 
0402     info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
0403     info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
0404     info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
0405 }
0406 
0407 static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
0408 {
0409     info->reg_cntfrq = arch_timer_get_cntfrq();
0410     /*
0411      * Use the effective value of the CTR_EL0 than the raw value
0412      * exposed by the CPU. CTR_EL0.IDC field value must be interpreted
0413      * with the CLIDR_EL1 fields to avoid triggering false warnings
0414      * when there is a mismatch across the CPUs. Keep track of the
0415      * effective value of the CTR_EL0 in our internal records for
0416      * accurate sanity check and feature enablement.
0417      */
0418     info->reg_ctr = read_cpuid_effective_cachetype();
0419     info->reg_dczid = read_cpuid(DCZID_EL0);
0420     info->reg_midr = read_cpuid_id();
0421     info->reg_revidr = read_cpuid(REVIDR_EL1);
0422 
0423     info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
0424     info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
0425     info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
0426     info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
0427     info->reg_id_aa64isar2 = read_cpuid(ID_AA64ISAR2_EL1);
0428     info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
0429     info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
0430     info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
0431     info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
0432     info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
0433     info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
0434     info->reg_id_aa64smfr0 = read_cpuid(ID_AA64SMFR0_EL1);
0435 
0436     if (id_aa64pfr1_mte(info->reg_id_aa64pfr1))
0437         info->reg_gmid = read_cpuid(GMID_EL1);
0438 
0439     if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
0440         __cpuinfo_store_cpu_32bit(&info->aarch32);
0441 
0442     cpuinfo_detect_icache_policy(info);
0443 }
0444 
0445 void cpuinfo_store_cpu(void)
0446 {
0447     struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
0448     __cpuinfo_store_cpu(info);
0449     update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
0450 }
0451 
0452 void __init cpuinfo_store_boot_cpu(void)
0453 {
0454     struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
0455     __cpuinfo_store_cpu(info);
0456 
0457     boot_cpu_data = *info;
0458     init_cpu_features(&boot_cpu_data);
0459 }