linux/arch/arm64/kernel/cpuinfo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Record and handle CPU attributes.
   4 *
   5 * Copyright (C) 2014 ARM Ltd.
   6 */
   7#include <asm/arch_timer.h>
   8#include <asm/cache.h>
   9#include <asm/cpu.h>
  10#include <asm/cputype.h>
  11#include <asm/cpufeature.h>
  12#include <asm/fpsimd.h>
  13
  14#include <linux/bitops.h>
  15#include <linux/bug.h>
  16#include <linux/compat.h>
  17#include <linux/elf.h>
  18#include <linux/init.h>
  19#include <linux/kernel.h>
  20#include <linux/personality.h>
  21#include <linux/preempt.h>
  22#include <linux/printk.h>
  23#include <linux/seq_file.h>
  24#include <linux/sched.h>
  25#include <linux/smp.h>
  26#include <linux/delay.h>
  27
  28/*
  29 * In case the boot CPU is hotpluggable, we record its initial state and
  30 * current state separately. Certain system registers may contain different
  31 * values depending on configuration at or after reset.
  32 */
  33DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
  34static struct cpuinfo_arm64 boot_cpu_data;
  35
  36static const char *icache_policy_str[] = {
  37        [0 ... ICACHE_POLICY_PIPT]      = "RESERVED/UNKNOWN",
  38        [ICACHE_POLICY_VIPT]            = "VIPT",
  39        [ICACHE_POLICY_PIPT]            = "PIPT",
  40        [ICACHE_POLICY_VPIPT]           = "VPIPT",
  41};
  42
  43unsigned long __icache_flags;
  44
  45static const char *const hwcap_str[] = {
  46        "fp",
  47        "asimd",
  48        "evtstrm",
  49        "aes",
  50        "pmull",
  51        "sha1",
  52        "sha2",
  53        "crc32",
  54        "atomics",
  55        "fphp",
  56        "asimdhp",
  57        "cpuid",
  58        "asimdrdm",
  59        "jscvt",
  60        "fcma",
  61        "lrcpc",
  62        "dcpop",
  63        "sha3",
  64        "sm3",
  65        "sm4",
  66        "asimddp",
  67        "sha512",
  68        "sve",
  69        "asimdfhm",
  70        "dit",
  71        "uscat",
  72        "ilrcpc",
  73        "flagm",
  74        "ssbs",
  75        "sb",
  76        "paca",
  77        "pacg",
  78        "dcpodp",
  79        "sve2",
  80        "sveaes",
  81        "svepmull",
  82        "svebitperm",
  83        "svesha3",
  84        "svesm4",
  85        "flagm2",
  86        "frint",
  87        "svei8mm",
  88        "svef32mm",
  89        "svef64mm",
  90        "svebf16",
  91        "i8mm",
  92        "bf16",
  93        "dgh",
  94        "rng",
  95        "bti",
  96        /* reserved for "mte" */
  97        NULL
  98};
  99
 100#ifdef CONFIG_COMPAT
 101static const char *const compat_hwcap_str[] = {
 102        "swp",
 103        "half",
 104        "thumb",
 105        "26bit",
 106        "fastmult",
 107        "fpa",
 108        "vfp",
 109        "edsp",
 110        "java",
 111        "iwmmxt",
 112        "crunch",
 113        "thumbee",
 114        "neon",
 115        "vfpv3",
 116        "vfpv3d16",
 117        "tls",
 118        "vfpv4",
 119        "idiva",
 120        "idivt",
 121        "vfpd32",
 122        "lpae",
 123        "evtstrm",
 124        NULL
 125};
 126
 127static const char *const compat_hwcap2_str[] = {
 128        "aes",
 129        "pmull",
 130        "sha1",
 131        "sha2",
 132        "crc32",
 133        NULL
 134};
 135#endif /* CONFIG_COMPAT */
 136
 137static int c_show(struct seq_file *m, void *v)
 138{
 139        int i, j;
 140        bool compat = personality(current->personality) == PER_LINUX32;
 141
 142        for_each_online_cpu(i) {
 143                struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
 144                u32 midr = cpuinfo->reg_midr;
 145
 146                /*
 147                 * glibc reads /proc/cpuinfo to determine the number of
 148                 * online processors, looking for lines beginning with
 149                 * "processor".  Give glibc what it expects.
 150                 */
 151                seq_printf(m, "processor\t: %d\n", i);
 152                if (compat)
 153                        seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
 154                                   MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
 155
 156                seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
 157                           loops_per_jiffy / (500000UL/HZ),
 158                           loops_per_jiffy / (5000UL/HZ) % 100);
 159
 160                /*
 161                 * Dump out the common processor features in a single line.
 162                 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
 163                 * rather than attempting to parse this, but there's a body of
 164                 * software which does already (at least for 32-bit).
 165                 */
 166                seq_puts(m, "Features\t:");
 167                if (compat) {
 168#ifdef CONFIG_COMPAT
 169                        for (j = 0; compat_hwcap_str[j]; j++)
 170                                if (compat_elf_hwcap & (1 << j))
 171                                        seq_printf(m, " %s", compat_hwcap_str[j]);
 172
 173                        for (j = 0; compat_hwcap2_str[j]; j++)
 174                                if (compat_elf_hwcap2 & (1 << j))
 175                                        seq_printf(m, " %s", compat_hwcap2_str[j]);
 176#endif /* CONFIG_COMPAT */
 177                } else {
 178                        for (j = 0; hwcap_str[j]; j++)
 179                                if (cpu_have_feature(j))
 180                                        seq_printf(m, " %s", hwcap_str[j]);
 181                }
 182                seq_puts(m, "\n");
 183
 184                seq_printf(m, "CPU implementer\t: 0x%02x\n",
 185                           MIDR_IMPLEMENTOR(midr));
 186                seq_printf(m, "CPU architecture: 8\n");
 187                seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
 188                seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
 189                seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
 190        }
 191
 192        return 0;
 193}
 194
 195static void *c_start(struct seq_file *m, loff_t *pos)
 196{
 197        return *pos < 1 ? (void *)1 : NULL;
 198}
 199
 200static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 201{
 202        ++*pos;
 203        return NULL;
 204}
 205
 206static void c_stop(struct seq_file *m, void *v)
 207{
 208}
 209
 210const struct seq_operations cpuinfo_op = {
 211        .start  = c_start,
 212        .next   = c_next,
 213        .stop   = c_stop,
 214        .show   = c_show
 215};
 216
 217
 218static struct kobj_type cpuregs_kobj_type = {
 219        .sysfs_ops = &kobj_sysfs_ops,
 220};
 221
 222/*
 223 * The ARM ARM uses the phrase "32-bit register" to describe a register
 224 * whose upper 32 bits are RES0 (per C5.1.1, ARM DDI 0487A.i), however
 225 * no statement is made as to whether the upper 32 bits will or will not
 226 * be made use of in future, and between ARM DDI 0487A.c and ARM DDI
 227 * 0487A.d CLIDR_EL1 was expanded from 32-bit to 64-bit.
 228 *
 229 * Thus, while both MIDR_EL1 and REVIDR_EL1 are described as 32-bit
 230 * registers, we expose them both as 64 bit values to cater for possible
 231 * future expansion without an ABI break.
 232 */
 233#define kobj_to_cpuinfo(kobj)   container_of(kobj, struct cpuinfo_arm64, kobj)
 234#define CPUREGS_ATTR_RO(_name, _field)                                          \
 235        static ssize_t _name##_show(struct kobject *kobj,                       \
 236                        struct kobj_attribute *attr, char *buf)                 \
 237        {                                                                       \
 238                struct cpuinfo_arm64 *info = kobj_to_cpuinfo(kobj);             \
 239                                                                                \
 240                if (info->reg_midr)                                             \
 241                        return sprintf(buf, "0x%016x\n", info->reg_##_field);   \
 242                else                                                            \
 243                        return 0;                                               \
 244        }                                                                       \
 245        static struct kobj_attribute cpuregs_attr_##_name = __ATTR_RO(_name)
 246
 247CPUREGS_ATTR_RO(midr_el1, midr);
 248CPUREGS_ATTR_RO(revidr_el1, revidr);
 249
 250static struct attribute *cpuregs_id_attrs[] = {
 251        &cpuregs_attr_midr_el1.attr,
 252        &cpuregs_attr_revidr_el1.attr,
 253        NULL
 254};
 255
 256static const struct attribute_group cpuregs_attr_group = {
 257        .attrs = cpuregs_id_attrs,
 258        .name = "identification"
 259};
 260
 261static int cpuid_cpu_online(unsigned int cpu)
 262{
 263        int rc;
 264        struct device *dev;
 265        struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
 266
 267        dev = get_cpu_device(cpu);
 268        if (!dev) {
 269                rc = -ENODEV;
 270                goto out;
 271        }
 272        rc = kobject_add(&info->kobj, &dev->kobj, "regs");
 273        if (rc)
 274                goto out;
 275        rc = sysfs_create_group(&info->kobj, &cpuregs_attr_group);
 276        if (rc)
 277                kobject_del(&info->kobj);
 278out:
 279        return rc;
 280}
 281
 282static int cpuid_cpu_offline(unsigned int cpu)
 283{
 284        struct device *dev;
 285        struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
 286
 287        dev = get_cpu_device(cpu);
 288        if (!dev)
 289                return -ENODEV;
 290        if (info->kobj.parent) {
 291                sysfs_remove_group(&info->kobj, &cpuregs_attr_group);
 292                kobject_del(&info->kobj);
 293        }
 294
 295        return 0;
 296}
 297
 298static int __init cpuinfo_regs_init(void)
 299{
 300        int cpu, ret;
 301
 302        for_each_possible_cpu(cpu) {
 303                struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
 304
 305                kobject_init(&info->kobj, &cpuregs_kobj_type);
 306        }
 307
 308        ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/cpuinfo:online",
 309                                cpuid_cpu_online, cpuid_cpu_offline);
 310        if (ret < 0) {
 311                pr_err("cpuinfo: failed to register hotplug callbacks.\n");
 312                return ret;
 313        }
 314        return 0;
 315}
 316device_initcall(cpuinfo_regs_init);
 317
 318static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
 319{
 320        unsigned int cpu = smp_processor_id();
 321        u32 l1ip = CTR_L1IP(info->reg_ctr);
 322
 323        switch (l1ip) {
 324        case ICACHE_POLICY_PIPT:
 325                break;
 326        case ICACHE_POLICY_VPIPT:
 327                set_bit(ICACHEF_VPIPT, &__icache_flags);
 328                break;
 329        default:
 330        case ICACHE_POLICY_VIPT:
 331                /* Assume aliasing */
 332                set_bit(ICACHEF_ALIASING, &__icache_flags);
 333        }
 334
 335        pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
 336}
 337
 338static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
 339{
 340        info->reg_cntfrq = arch_timer_get_cntfrq();
 341        /*
 342         * Use the effective value of the CTR_EL0 than the raw value
 343         * exposed by the CPU. CTR_EL0.IDC field value must be interpreted
 344         * with the CLIDR_EL1 fields to avoid triggering false warnings
 345         * when there is a mismatch across the CPUs. Keep track of the
 346         * effective value of the CTR_EL0 in our internal records for
 347         * acurate sanity check and feature enablement.
 348         */
 349        info->reg_ctr = read_cpuid_effective_cachetype();
 350        info->reg_dczid = read_cpuid(DCZID_EL0);
 351        info->reg_midr = read_cpuid_id();
 352        info->reg_revidr = read_cpuid(REVIDR_EL1);
 353
 354        info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
 355        info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
 356        info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
 357        info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
 358        info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
 359        info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
 360        info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
 361        info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
 362        info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
 363        info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
 364
 365        /* Update the 32bit ID registers only if AArch32 is implemented */
 366        if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
 367                info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
 368                info->reg_id_dfr1 = read_cpuid(ID_DFR1_EL1);
 369                info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
 370                info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
 371                info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
 372                info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
 373                info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
 374                info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
 375                info->reg_id_isar6 = read_cpuid(ID_ISAR6_EL1);
 376                info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
 377                info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
 378                info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
 379                info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
 380                info->reg_id_mmfr4 = read_cpuid(ID_MMFR4_EL1);
 381                info->reg_id_mmfr5 = read_cpuid(ID_MMFR5_EL1);
 382                info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
 383                info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
 384                info->reg_id_pfr2 = read_cpuid(ID_PFR2_EL1);
 385
 386                info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
 387                info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
 388                info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
 389        }
 390
 391        if (IS_ENABLED(CONFIG_ARM64_SVE) &&
 392            id_aa64pfr0_sve(info->reg_id_aa64pfr0))
 393                info->reg_zcr = read_zcr_features();
 394
 395        cpuinfo_detect_icache_policy(info);
 396}
 397
 398void cpuinfo_store_cpu(void)
 399{
 400        struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
 401        __cpuinfo_store_cpu(info);
 402        update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
 403}
 404
 405void __init cpuinfo_store_boot_cpu(void)
 406{
 407        struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
 408        __cpuinfo_store_cpu(info);
 409
 410        boot_cpu_data = *info;
 411        init_cpu_features(&boot_cpu_data);
 412}
 413