13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * Record and handle CPU attributes. 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (C) 2014 ARM Ltd. 63d0407baSopenharmony_ci */ 73d0407baSopenharmony_ci#include <asm/arch_timer.h> 83d0407baSopenharmony_ci#include <asm/cache.h> 93d0407baSopenharmony_ci#include <asm/cpu.h> 103d0407baSopenharmony_ci#include <asm/cputype.h> 113d0407baSopenharmony_ci#include <asm/cpufeature.h> 123d0407baSopenharmony_ci#include <asm/fpsimd.h> 133d0407baSopenharmony_ci 143d0407baSopenharmony_ci#include <linux/bitops.h> 153d0407baSopenharmony_ci#include <linux/bug.h> 163d0407baSopenharmony_ci#include <linux/compat.h> 173d0407baSopenharmony_ci#include <linux/elf.h> 183d0407baSopenharmony_ci#include <linux/init.h> 193d0407baSopenharmony_ci#include <linux/kernel.h> 203d0407baSopenharmony_ci#include <linux/personality.h> 213d0407baSopenharmony_ci#include <linux/preempt.h> 223d0407baSopenharmony_ci#include <linux/printk.h> 233d0407baSopenharmony_ci#include <linux/seq_file.h> 243d0407baSopenharmony_ci#include <linux/sched.h> 253d0407baSopenharmony_ci#include <linux/smp.h> 263d0407baSopenharmony_ci#include <linux/delay.h> 273d0407baSopenharmony_ci 283d0407baSopenharmony_ciunsigned int system_serial_low; 293d0407baSopenharmony_ciEXPORT_SYMBOL(system_serial_low); 303d0407baSopenharmony_ci 313d0407baSopenharmony_ciunsigned int system_serial_high; 323d0407baSopenharmony_ciEXPORT_SYMBOL(system_serial_high); 333d0407baSopenharmony_ci 343d0407baSopenharmony_ci/* 353d0407baSopenharmony_ci * In case the boot CPU is hotpluggable, we record its initial state and 363d0407baSopenharmony_ci * current state separately. Certain system registers may contain different 373d0407baSopenharmony_ci * values depending on configuration at or after reset. 383d0407baSopenharmony_ci */ 393d0407baSopenharmony_ciDEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data); 403d0407baSopenharmony_cistatic struct cpuinfo_arm64 boot_cpu_data; 413d0407baSopenharmony_ci 423d0407baSopenharmony_cistatic const char *icache_policy_str[] = { 433d0407baSopenharmony_ci [ICACHE_POLICY_VPIPT] = "VPIPT", 443d0407baSopenharmony_ci [ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN", 453d0407baSopenharmony_ci [ICACHE_POLICY_VIPT] = "VIPT", 463d0407baSopenharmony_ci [ICACHE_POLICY_PIPT] = "PIPT", 473d0407baSopenharmony_ci}; 483d0407baSopenharmony_ci 493d0407baSopenharmony_ciunsigned long __icache_flags; 503d0407baSopenharmony_ci 513d0407baSopenharmony_cistatic const char *const hwcap_str[] = { 523d0407baSopenharmony_ci [KERNEL_HWCAP_FP] = "fp", 533d0407baSopenharmony_ci [KERNEL_HWCAP_ASIMD] = "asimd", 543d0407baSopenharmony_ci [KERNEL_HWCAP_EVTSTRM] = "evtstrm", 553d0407baSopenharmony_ci [KERNEL_HWCAP_AES] = "aes", 563d0407baSopenharmony_ci [KERNEL_HWCAP_PMULL] = "pmull", 573d0407baSopenharmony_ci [KERNEL_HWCAP_SHA1] = "sha1", 583d0407baSopenharmony_ci [KERNEL_HWCAP_SHA2] = "sha2", 593d0407baSopenharmony_ci [KERNEL_HWCAP_CRC32] = "crc32", 603d0407baSopenharmony_ci [KERNEL_HWCAP_ATOMICS] = "atomics", 613d0407baSopenharmony_ci [KERNEL_HWCAP_FPHP] = "fphp", 623d0407baSopenharmony_ci [KERNEL_HWCAP_ASIMDHP] = "asimdhp", 633d0407baSopenharmony_ci [KERNEL_HWCAP_CPUID] = "cpuid", 643d0407baSopenharmony_ci [KERNEL_HWCAP_ASIMDRDM] = "asimdrdm", 653d0407baSopenharmony_ci [KERNEL_HWCAP_JSCVT] = "jscvt", 663d0407baSopenharmony_ci [KERNEL_HWCAP_FCMA] = "fcma", 673d0407baSopenharmony_ci [KERNEL_HWCAP_LRCPC] = "lrcpc", 683d0407baSopenharmony_ci [KERNEL_HWCAP_DCPOP] = "dcpop", 693d0407baSopenharmony_ci [KERNEL_HWCAP_SHA3] = "sha3", 703d0407baSopenharmony_ci [KERNEL_HWCAP_SM3] = "sm3", 713d0407baSopenharmony_ci [KERNEL_HWCAP_SM4] = "sm4", 723d0407baSopenharmony_ci [KERNEL_HWCAP_ASIMDDP] = "asimddp", 733d0407baSopenharmony_ci [KERNEL_HWCAP_SHA512] = "sha512", 743d0407baSopenharmony_ci [KERNEL_HWCAP_SVE] = "sve", 753d0407baSopenharmony_ci [KERNEL_HWCAP_ASIMDFHM] = "asimdfhm", 763d0407baSopenharmony_ci [KERNEL_HWCAP_DIT] = "dit", 773d0407baSopenharmony_ci [KERNEL_HWCAP_USCAT] = "uscat", 783d0407baSopenharmony_ci [KERNEL_HWCAP_ILRCPC] = "ilrcpc", 793d0407baSopenharmony_ci [KERNEL_HWCAP_FLAGM] = "flagm", 803d0407baSopenharmony_ci [KERNEL_HWCAP_SSBS] = "ssbs", 813d0407baSopenharmony_ci [KERNEL_HWCAP_SB] = "sb", 823d0407baSopenharmony_ci [KERNEL_HWCAP_PACA] = "paca", 833d0407baSopenharmony_ci [KERNEL_HWCAP_PACG] = "pacg", 843d0407baSopenharmony_ci [KERNEL_HWCAP_DCPODP] = "dcpodp", 853d0407baSopenharmony_ci [KERNEL_HWCAP_SVE2] = "sve2", 863d0407baSopenharmony_ci [KERNEL_HWCAP_SVEAES] = "sveaes", 873d0407baSopenharmony_ci [KERNEL_HWCAP_SVEPMULL] = "svepmull", 883d0407baSopenharmony_ci [KERNEL_HWCAP_SVEBITPERM] = "svebitperm", 893d0407baSopenharmony_ci [KERNEL_HWCAP_SVESHA3] = "svesha3", 903d0407baSopenharmony_ci [KERNEL_HWCAP_SVESM4] = "svesm4", 913d0407baSopenharmony_ci [KERNEL_HWCAP_FLAGM2] = "flagm2", 923d0407baSopenharmony_ci [KERNEL_HWCAP_FRINT] = "frint", 933d0407baSopenharmony_ci [KERNEL_HWCAP_SVEI8MM] = "svei8mm", 943d0407baSopenharmony_ci [KERNEL_HWCAP_SVEF32MM] = "svef32mm", 953d0407baSopenharmony_ci [KERNEL_HWCAP_SVEF64MM] = "svef64mm", 963d0407baSopenharmony_ci [KERNEL_HWCAP_SVEBF16] = "svebf16", 973d0407baSopenharmony_ci [KERNEL_HWCAP_I8MM] = "i8mm", 983d0407baSopenharmony_ci [KERNEL_HWCAP_BF16] = "bf16", 993d0407baSopenharmony_ci [KERNEL_HWCAP_DGH] = "dgh", 1003d0407baSopenharmony_ci [KERNEL_HWCAP_RNG] = "rng", 1013d0407baSopenharmony_ci [KERNEL_HWCAP_BTI] = "bti", 1023d0407baSopenharmony_ci [KERNEL_HWCAP_MTE] = "mte", 1033d0407baSopenharmony_ci [KERNEL_HWCAP_ECV] = "ecv", 1043d0407baSopenharmony_ci [KERNEL_HWCAP_AFP] = "afp", 1053d0407baSopenharmony_ci [KERNEL_HWCAP_RPRES] = "rpres", 1063d0407baSopenharmony_ci}; 1073d0407baSopenharmony_ci 1083d0407baSopenharmony_ci#ifdef CONFIG_COMPAT 1093d0407baSopenharmony_ci#define COMPAT_KERNEL_HWCAP(x) const_ilog2(COMPAT_HWCAP_##x) 1103d0407baSopenharmony_cistatic const char *const compat_hwcap_str[] = { 1113d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(SWP)] = "swp", 1123d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(HALF)] = "half", 1133d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(THUMB)] = "thumb", 1143d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(26BIT)] = NULL, /* Not possible on arm64 */ 1153d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(FAST_MULT)] = "fastmult", 1163d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(FPA)] = NULL, /* Not possible on arm64 */ 1173d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(VFP)] = "vfp", 1183d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(EDSP)] = "edsp", 1193d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(JAVA)] = NULL, /* Not possible on arm64 */ 1203d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(IWMMXT)] = NULL, /* Not possible on arm64 */ 1213d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(CRUNCH)] = NULL, /* Not possible on arm64 */ 1223d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(THUMBEE)] = NULL, /* Not possible on arm64 */ 1233d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(NEON)] = "neon", 1243d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(VFPv3)] = "vfpv3", 1253d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(VFPV3D16)] = NULL, /* Not possible on arm64 */ 1263d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(TLS)] = "tls", 1273d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(VFPv4)] = "vfpv4", 1283d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(IDIVA)] = "idiva", 1293d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(IDIVT)] = "idivt", 1303d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(VFPD32)] = NULL, /* Not possible on arm64 */ 1313d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(LPAE)] = "lpae", 1323d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP(EVTSTRM)] = "evtstrm", 1333d0407baSopenharmony_ci}; 1343d0407baSopenharmony_ci 1353d0407baSopenharmony_ci#define COMPAT_KERNEL_HWCAP2(x) const_ilog2(COMPAT_HWCAP2_##x) 1363d0407baSopenharmony_cistatic const char *const compat_hwcap2_str[] = { 1373d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP2(AES)] = "aes", [COMPAT_KERNEL_HWCAP2(PMULL)] = "pmull", 1383d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP2(SHA1)] = "sha1", [COMPAT_KERNEL_HWCAP2(SHA2)] = "sha2", 1393d0407baSopenharmony_ci [COMPAT_KERNEL_HWCAP2(CRC32)] = "crc32", 1403d0407baSopenharmony_ci}; 1413d0407baSopenharmony_ci#endif /* CONFIG_COMPAT */ 1423d0407baSopenharmony_ci 1433d0407baSopenharmony_cistatic int c_show(struct seq_file *m, void *v) 1443d0407baSopenharmony_ci{ 1453d0407baSopenharmony_ci int i, j; 1463d0407baSopenharmony_ci bool compat = personality(current->personality) == PER_LINUX32; 1473d0407baSopenharmony_ci 1483d0407baSopenharmony_ci for_each_online_cpu(i) 1493d0407baSopenharmony_ci { 1503d0407baSopenharmony_ci struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); 1513d0407baSopenharmony_ci u32 midr = cpuinfo->reg_midr; 1523d0407baSopenharmony_ci 1533d0407baSopenharmony_ci /* 1543d0407baSopenharmony_ci * glibc reads /proc/cpuinfo to determine the number of 1553d0407baSopenharmony_ci * online processors, looking for lines beginning with 1563d0407baSopenharmony_ci * "processor". Give glibc what it expects. 1573d0407baSopenharmony_ci */ 1583d0407baSopenharmony_ci seq_printf(m, "processor\t: %d\n", i); 1593d0407baSopenharmony_ci if (compat) { 1603d0407baSopenharmony_ci seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); 1613d0407baSopenharmony_ci } 1623d0407baSopenharmony_ci 1633d0407baSopenharmony_ci seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", loops_per_jiffy / (500000UL / HZ), 1643d0407baSopenharmony_ci loops_per_jiffy / (5000UL / HZ) % 0x64); 1653d0407baSopenharmony_ci 1663d0407baSopenharmony_ci /* 1673d0407baSopenharmony_ci * Dump out the common processor features in a single line. 1683d0407baSopenharmony_ci * Userspace should read the hwcaps with getauxval(AT_HWCAP) 1693d0407baSopenharmony_ci * rather than attempting to parse this, but there's a body of 1703d0407baSopenharmony_ci * software which does already (at least for 32-bit). 1713d0407baSopenharmony_ci */ 1723d0407baSopenharmony_ci seq_puts(m, "Features\t:"); 1733d0407baSopenharmony_ci if (compat) { 1743d0407baSopenharmony_ci#ifdef CONFIG_COMPAT 1753d0407baSopenharmony_ci for (j = 0; j < ARRAY_SIZE(compat_hwcap_str); j++) { 1763d0407baSopenharmony_ci if (compat_elf_hwcap & (1 << j)) { 1773d0407baSopenharmony_ci /* 1783d0407baSopenharmony_ci * Warn once if any feature should not 1793d0407baSopenharmony_ci * have been present on arm64 platform. 1803d0407baSopenharmony_ci */ 1813d0407baSopenharmony_ci if (WARN_ON_ONCE(!compat_hwcap_str[j])) { 1823d0407baSopenharmony_ci continue; 1833d0407baSopenharmony_ci } 1843d0407baSopenharmony_ci 1853d0407baSopenharmony_ci seq_printf(m, " %s", compat_hwcap_str[j]); 1863d0407baSopenharmony_ci } 1873d0407baSopenharmony_ci } 1883d0407baSopenharmony_ci 1893d0407baSopenharmony_ci for (j = 0; j < ARRAY_SIZE(compat_hwcap2_str); j++) { 1903d0407baSopenharmony_ci if (compat_elf_hwcap2 & (1 << j)) { 1913d0407baSopenharmony_ci seq_printf(m, " %s", compat_hwcap2_str[j]); 1923d0407baSopenharmony_ci } 1933d0407baSopenharmony_ci } 1943d0407baSopenharmony_ci#endif /* CONFIG_COMPAT */ 1953d0407baSopenharmony_ci } else { 1963d0407baSopenharmony_ci for (j = 0; j < ARRAY_SIZE(hwcap_str); j++) { 1973d0407baSopenharmony_ci if (cpu_have_feature(j)) { 1983d0407baSopenharmony_ci seq_printf(m, " %s", hwcap_str[j]); 1993d0407baSopenharmony_ci } 2003d0407baSopenharmony_ci } 2013d0407baSopenharmony_ci } 2023d0407baSopenharmony_ci seq_puts(m, "\n"); 2033d0407baSopenharmony_ci 2043d0407baSopenharmony_ci seq_printf(m, "CPU implementer\t: 0x%02x\n", MIDR_IMPLEMENTOR(midr)); 2053d0407baSopenharmony_ci seq_printf(m, "CPU architecture: 8\n"); 2063d0407baSopenharmony_ci seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr)); 2073d0407baSopenharmony_ci seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr)); 2083d0407baSopenharmony_ci seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr)); 2093d0407baSopenharmony_ci } 2103d0407baSopenharmony_ci 2113d0407baSopenharmony_ci return 0; 2123d0407baSopenharmony_ci} 2133d0407baSopenharmony_ci 2143d0407baSopenharmony_cistatic void *c_start(struct seq_file *m, loff_t *pos) 2153d0407baSopenharmony_ci{ 2163d0407baSopenharmony_ci return *pos < 1 ? (void *)1 : NULL; 2173d0407baSopenharmony_ci} 2183d0407baSopenharmony_ci 2193d0407baSopenharmony_cistatic void *c_next(struct seq_file *m, void *v, loff_t *pos) 2203d0407baSopenharmony_ci{ 2213d0407baSopenharmony_ci ++*pos; 2223d0407baSopenharmony_ci return NULL; 2233d0407baSopenharmony_ci} 2243d0407baSopenharmony_ci 2253d0407baSopenharmony_cistatic void c_stop(struct seq_file *m, void *v) 2263d0407baSopenharmony_ci{ 2273d0407baSopenharmony_ci} 2283d0407baSopenharmony_ci 2293d0407baSopenharmony_ciconst struct seq_operations cpuinfo_op = {.start = c_start, .next = c_next, .stop = c_stop, .show = c_show}; 2303d0407baSopenharmony_ci 2313d0407baSopenharmony_cistatic struct kobj_type cpuregs_kobj_type = { 2323d0407baSopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 2333d0407baSopenharmony_ci}; 2343d0407baSopenharmony_ci 2353d0407baSopenharmony_ci/* 2363d0407baSopenharmony_ci * The ARM ARM uses the phrase "32-bit register" to describe a register 2373d0407baSopenharmony_ci * whose upper 32 bits are RES0 (per C5.1.1, ARM DDI 0487A.i), however 2383d0407baSopenharmony_ci * no statement is made as to whether the upper 32 bits will or will not 2393d0407baSopenharmony_ci * be made use of in future, and between ARM DDI 0487A.c and ARM DDI 2403d0407baSopenharmony_ci * 0487A.d CLIDR_EL1 was expanded from 32-bit to 64-bit. 2413d0407baSopenharmony_ci * 2423d0407baSopenharmony_ci * Thus, while both MIDR_EL1 and REVIDR_EL1 are described as 32-bit 2433d0407baSopenharmony_ci * registers, we expose them both as 64 bit values to cater for possible 2443d0407baSopenharmony_ci * future expansion without an ABI break. 2453d0407baSopenharmony_ci */ 2463d0407baSopenharmony_ci#define kobj_to_cpuinfo(kobj) container_of(kobj, struct cpuinfo_arm64, kobj) 2473d0407baSopenharmony_ci#define CPUREGS_ATTR_RO(_name, _field) \ 2483d0407baSopenharmony_ci static ssize_t _name##_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ 2493d0407baSopenharmony_ci { \ 2503d0407baSopenharmony_ci struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj); \ 2513d0407baSopenharmony_ci \ 2523d0407baSopenharmony_ci if (info->reg_midr) \ 2533d0407baSopenharmony_ci return sprintf(buf, "0x%016x\n", info->reg_##_field); \ 2543d0407baSopenharmony_ci else \ 2553d0407baSopenharmony_ci return 0; \ 2563d0407baSopenharmony_ci } \ 2573d0407baSopenharmony_ci static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RO(_name) 2583d0407baSopenharmony_ci 2593d0407baSopenharmony_ciCPUREGS_ATTR_RO(midr_el1, midr); 2603d0407baSopenharmony_ciCPUREGS_ATTR_RO(revidr_el1, revidr); 2613d0407baSopenharmony_ci 2623d0407baSopenharmony_cistatic struct attribute *cpuregs_id_attrs[] = {&cpuregs_attr_midr_el1.attr, &cpuregs_attr_revidr_el1.attr, NULL}; 2633d0407baSopenharmony_ci 2643d0407baSopenharmony_cistatic const struct attribute_group cpuregs_attr_group = {.attrs = cpuregs_id_attrs, .name = "identification"}; 2653d0407baSopenharmony_ci 2663d0407baSopenharmony_cistatic int cpuid_cpu_online(unsigned int cpu) 2673d0407baSopenharmony_ci{ 2683d0407baSopenharmony_ci int rc; 2693d0407baSopenharmony_ci struct device *dev; 2703d0407baSopenharmony_ci struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu); 2713d0407baSopenharmony_ci 2723d0407baSopenharmony_ci dev = get_cpu_device(cpu); 2733d0407baSopenharmony_ci if (!dev) { 2743d0407baSopenharmony_ci rc = -ENODEV; 2753d0407baSopenharmony_ci goto out; 2763d0407baSopenharmony_ci } 2773d0407baSopenharmony_ci rc = kobject_add(&info->kobj, &dev->kobj, "regs"); 2783d0407baSopenharmony_ci if (rc) { 2793d0407baSopenharmony_ci goto out; 2803d0407baSopenharmony_ci } 2813d0407baSopenharmony_ci rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group); 2823d0407baSopenharmony_ci if (rc) { 2833d0407baSopenharmony_ci kobject_del(&info->kobj); 2843d0407baSopenharmony_ci } 2853d0407baSopenharmony_ciout: 2863d0407baSopenharmony_ci return rc; 2873d0407baSopenharmony_ci} 2883d0407baSopenharmony_ci 2893d0407baSopenharmony_cistatic int cpuid_cpu_offline(unsigned int cpu) 2903d0407baSopenharmony_ci{ 2913d0407baSopenharmony_ci struct device *dev; 2923d0407baSopenharmony_ci struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu); 2933d0407baSopenharmony_ci 2943d0407baSopenharmony_ci dev = get_cpu_device(cpu); 2953d0407baSopenharmony_ci if (!dev) { 2963d0407baSopenharmony_ci return -ENODEV; 2973d0407baSopenharmony_ci } 2983d0407baSopenharmony_ci if (info->kobj.parent) { 2993d0407baSopenharmony_ci sysfs_remove_group(&info->kobj, &cpuregs_attr_group); 3003d0407baSopenharmony_ci kobject_del(&info->kobj); 3013d0407baSopenharmony_ci } 3023d0407baSopenharmony_ci 3033d0407baSopenharmony_ci return 0; 3043d0407baSopenharmony_ci} 3053d0407baSopenharmony_ci 3063d0407baSopenharmony_cistatic int __init cpuinfo_regs_init(void) 3073d0407baSopenharmony_ci{ 3083d0407baSopenharmony_ci int cpu, ret; 3093d0407baSopenharmony_ci 3103d0407baSopenharmony_ci for_each_possible_cpu(cpu) 3113d0407baSopenharmony_ci { 3123d0407baSopenharmony_ci struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu); 3133d0407baSopenharmony_ci 3143d0407baSopenharmony_ci kobject_init(&info->kobj, &cpuregs_kobj_type); 3153d0407baSopenharmony_ci } 3163d0407baSopenharmony_ci 3173d0407baSopenharmony_ci ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/cpuinfo:online", cpuid_cpu_online, cpuid_cpu_offline); 3183d0407baSopenharmony_ci if (ret < 0) { 3193d0407baSopenharmony_ci pr_err("cpuinfo: failed to register hotplug callbacks.\n"); 3203d0407baSopenharmony_ci return ret; 3213d0407baSopenharmony_ci } 3223d0407baSopenharmony_ci return 0; 3233d0407baSopenharmony_ci} 3243d0407baSopenharmony_cidevice_initcall(cpuinfo_regs_init); 3253d0407baSopenharmony_ci 3263d0407baSopenharmony_cistatic void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) 3273d0407baSopenharmony_ci{ 3283d0407baSopenharmony_ci unsigned int cpu = smp_processor_id(); 3293d0407baSopenharmony_ci u32 l1ip = CTR_L1IP(info->reg_ctr); 3303d0407baSopenharmony_ci 3313d0407baSopenharmony_ci switch (l1ip) { 3323d0407baSopenharmony_ci case ICACHE_POLICY_PIPT: 3333d0407baSopenharmony_ci break; 3343d0407baSopenharmony_ci case ICACHE_POLICY_VPIPT: 3353d0407baSopenharmony_ci set_bit(ICACHEF_VPIPT, &__icache_flags); 3363d0407baSopenharmony_ci break; 3373d0407baSopenharmony_ci case ICACHE_POLICY_RESERVED: 3383d0407baSopenharmony_ci case ICACHE_POLICY_VIPT: 3393d0407baSopenharmony_ci /* Assume aliasing */ 3403d0407baSopenharmony_ci set_bit(ICACHEF_ALIASING, &__icache_flags); 3413d0407baSopenharmony_ci break; 3423d0407baSopenharmony_ci } 3433d0407baSopenharmony_ci 3443d0407baSopenharmony_ci pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); 3453d0407baSopenharmony_ci} 3463d0407baSopenharmony_ci 3473d0407baSopenharmony_cistatic void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) 3483d0407baSopenharmony_ci{ 3493d0407baSopenharmony_ci info->reg_cntfrq = arch_timer_get_cntfrq(); 3503d0407baSopenharmony_ci /* 3513d0407baSopenharmony_ci * Use the effective value of the CTR_EL0 than the raw value 3523d0407baSopenharmony_ci * exposed by the CPU. CTR_EL0.IDC field value must be interpreted 3533d0407baSopenharmony_ci * with the CLIDR_EL1 fields to avoid triggering false warnings 3543d0407baSopenharmony_ci * when there is a mismatch across the CPUs. Keep track of the 3553d0407baSopenharmony_ci * effective value of the CTR_EL0 in our internal records for 3563d0407baSopenharmony_ci * acurate sanity check and feature enablement. 3573d0407baSopenharmony_ci */ 3583d0407baSopenharmony_ci info->reg_ctr = read_cpuid_effective_cachetype(); 3593d0407baSopenharmony_ci info->reg_dczid = read_cpuid(DCZID_EL0); 3603d0407baSopenharmony_ci info->reg_midr = read_cpuid_id(); 3613d0407baSopenharmony_ci info->reg_revidr = read_cpuid(REVIDR_EL1); 3623d0407baSopenharmony_ci 3633d0407baSopenharmony_ci info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1); 3643d0407baSopenharmony_ci info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1); 3653d0407baSopenharmony_ci info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1); 3663d0407baSopenharmony_ci info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1); 3673d0407baSopenharmony_ci info->reg_id_aa64isar2 = read_cpuid(ID_AA64ISAR2_EL1); 3683d0407baSopenharmony_ci info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1); 3693d0407baSopenharmony_ci info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1); 3703d0407baSopenharmony_ci info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1); 3713d0407baSopenharmony_ci info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1); 3723d0407baSopenharmony_ci info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1); 3733d0407baSopenharmony_ci info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1); 3743d0407baSopenharmony_ci 3753d0407baSopenharmony_ci /* Update the 32bit ID registers only if AArch32 is implemented */ 3763d0407baSopenharmony_ci if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) { 3773d0407baSopenharmony_ci info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1); 3783d0407baSopenharmony_ci info->reg_id_dfr1 = read_cpuid(ID_DFR1_EL1); 3793d0407baSopenharmony_ci info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1); 3803d0407baSopenharmony_ci info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1); 3813d0407baSopenharmony_ci info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1); 3823d0407baSopenharmony_ci info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1); 3833d0407baSopenharmony_ci info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1); 3843d0407baSopenharmony_ci info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1); 3853d0407baSopenharmony_ci info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1); 3863d0407baSopenharmony_ci info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1); 3873d0407baSopenharmony_ci info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1); 3883d0407baSopenharmony_ci info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1); 3893d0407baSopenharmony_ci info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1); 3903d0407baSopenharmony_ci info->reg_id_mmfr4 = read_cpuid(ID_MMFR4_EL1); 3913d0407baSopenharmony_ci info->reg_id_mmfr5 = read_cpuid(ID_MMFR5_EL1); 3923d0407baSopenharmony_ci info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1); 3933d0407baSopenharmony_ci info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1); 3943d0407baSopenharmony_ci info->reg_id_pfr2 = read_cpuid(ID_PFR2_EL1); 3953d0407baSopenharmony_ci 3963d0407baSopenharmony_ci info->reg_mvfr0 = read_cpuid(MVFR0_EL1); 3973d0407baSopenharmony_ci info->reg_mvfr1 = read_cpuid(MVFR1_EL1); 3983d0407baSopenharmony_ci info->reg_mvfr2 = read_cpuid(MVFR2_EL1); 3993d0407baSopenharmony_ci } 4003d0407baSopenharmony_ci 4013d0407baSopenharmony_ci if (IS_ENABLED(CONFIG_ARM64_SVE) && id_aa64pfr0_sve(info->reg_id_aa64pfr0)) { 4023d0407baSopenharmony_ci info->reg_zcr = read_zcr_features(); 4033d0407baSopenharmony_ci } 4043d0407baSopenharmony_ci 4053d0407baSopenharmony_ci cpuinfo_detect_icache_policy(info); 4063d0407baSopenharmony_ci} 4073d0407baSopenharmony_ci 4083d0407baSopenharmony_civoid cpuinfo_store_cpu(void) 4093d0407baSopenharmony_ci{ 4103d0407baSopenharmony_ci struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data); 4113d0407baSopenharmony_ci __cpuinfo_store_cpu(info); 4123d0407baSopenharmony_ci update_cpu_features(smp_processor_id(), info, &boot_cpu_data); 4133d0407baSopenharmony_ci} 4143d0407baSopenharmony_ci 4153d0407baSopenharmony_civoid __init cpuinfo_store_boot_cpu(void) 4163d0407baSopenharmony_ci{ 4173d0407baSopenharmony_ci struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0); 4183d0407baSopenharmony_ci __cpuinfo_store_cpu(info); 4193d0407baSopenharmony_ci 4203d0407baSopenharmony_ci boot_cpu_data = *info; 4213d0407baSopenharmony_ci init_cpu_features(&boot_cpu_data); 4223d0407baSopenharmony_ci} 423