0001
0002
0003
0004
0005
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
0030
0031
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,
0127 [COMPAT_KERNEL_HWCAP(FAST_MULT)] = "fastmult",
0128 [COMPAT_KERNEL_HWCAP(FPA)] = NULL,
0129 [COMPAT_KERNEL_HWCAP(VFP)] = "vfp",
0130 [COMPAT_KERNEL_HWCAP(EDSP)] = "edsp",
0131 [COMPAT_KERNEL_HWCAP(JAVA)] = NULL,
0132 [COMPAT_KERNEL_HWCAP(IWMMXT)] = NULL,
0133 [COMPAT_KERNEL_HWCAP(CRUNCH)] = NULL,
0134 [COMPAT_KERNEL_HWCAP(THUMBEE)] = NULL,
0135 [COMPAT_KERNEL_HWCAP(NEON)] = "neon",
0136 [COMPAT_KERNEL_HWCAP(VFPv3)] = "vfpv3",
0137 [COMPAT_KERNEL_HWCAP(VFPV3D16)] = NULL,
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,
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
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
0168
0169
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
0182
0183
0184
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
0193
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
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
0253
0254
0255
0256
0257
0258
0259
0260
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
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
0412
0413
0414
0415
0416
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 }