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

arm64: cpuinfo: record cpu system register values

Several kernel subsystems need to know details about CPU system register
values, sometimes for CPUs other than that they are executing on. Rather
than hard-coding system register accesses and cross-calls for these
cases, this patch adds logic to record various system register values at
boot-time. This may be used for feature reporting, firmware bug
detection, etc.

Separate hooks are added for the boot and hotplug paths to enable
one-time intialisation and cold/warm boot value mismatch detection in
later patches.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Mark Rutland and committed by
Catalin Marinas
df857416 89c4a306

+144 -4
+59
arch/arm64/include/asm/cpu.h
··· 1 + /* 2 + * Copyright (C) 2014 ARM Ltd. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + */ 16 + #ifndef __ASM_CPU_H 17 + #define __ASM_CPU_H 18 + 19 + #include <linux/cpu.h> 20 + #include <linux/init.h> 21 + #include <linux/percpu.h> 22 + 23 + /* 24 + * Records attributes of an individual CPU. 25 + */ 26 + struct cpuinfo_arm64 { 27 + struct cpu cpu; 28 + u32 reg_ctr; 29 + u32 reg_cntfrq; 30 + u32 reg_dczid; 31 + u32 reg_midr; 32 + 33 + u64 reg_id_aa64isar0; 34 + u64 reg_id_aa64isar1; 35 + u64 reg_id_aa64mmfr0; 36 + u64 reg_id_aa64mmfr1; 37 + u64 reg_id_aa64pfr0; 38 + u64 reg_id_aa64pfr1; 39 + 40 + u32 reg_id_isar0; 41 + u32 reg_id_isar1; 42 + u32 reg_id_isar2; 43 + u32 reg_id_isar3; 44 + u32 reg_id_isar4; 45 + u32 reg_id_isar5; 46 + u32 reg_id_mmfr0; 47 + u32 reg_id_mmfr1; 48 + u32 reg_id_mmfr2; 49 + u32 reg_id_mmfr3; 50 + u32 reg_id_pfr0; 51 + u32 reg_id_pfr1; 52 + }; 53 + 54 + DECLARE_PER_CPU(struct cpuinfo_arm64, cpu_data); 55 + 56 + void cpuinfo_store_cpu(void); 57 + void __init cpuinfo_store_boot_cpu(void); 58 + 59 + #endif /* __ASM_CPU_H */
+2 -1
arch/arm64/kernel/Makefile
··· 15 15 arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ 16 16 entry-fpsimd.o process.o ptrace.o setup.o signal.o \ 17 17 sys.o stacktrace.o time.o traps.o io.o vdso.o \ 18 - hyp-stub.o psci.o cpu_ops.o insn.o return_address.o 18 + hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \ 19 + cpuinfo.o 19 20 20 21 arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ 21 22 sys_compat.o
+73
arch/arm64/kernel/cpuinfo.c
··· 1 + /* 2 + * Record and handle CPU attributes. 3 + * 4 + * Copyright (C) 2014 ARM Ltd. 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + #include <asm/arch_timer.h> 18 + #include <asm/cachetype.h> 19 + #include <asm/cpu.h> 20 + #include <asm/cputype.h> 21 + 22 + #include <linux/init.h> 23 + #include <linux/smp.h> 24 + 25 + /* 26 + * In case the boot CPU is hotpluggable, we record its initial state and 27 + * current state separately. Certain system registers may contain different 28 + * values depending on configuration at or after reset. 29 + */ 30 + DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data); 31 + static struct cpuinfo_arm64 boot_cpu_data; 32 + 33 + static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) 34 + { 35 + info->reg_cntfrq = arch_timer_get_cntfrq(); 36 + info->reg_ctr = read_cpuid_cachetype(); 37 + info->reg_dczid = read_cpuid(DCZID_EL0); 38 + info->reg_midr = read_cpuid_id(); 39 + 40 + info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1); 41 + info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1); 42 + info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1); 43 + info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1); 44 + info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1); 45 + info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1); 46 + 47 + info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1); 48 + info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1); 49 + info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1); 50 + info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1); 51 + info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1); 52 + info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1); 53 + info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1); 54 + info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1); 55 + info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1); 56 + info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1); 57 + info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1); 58 + info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1); 59 + } 60 + 61 + void cpuinfo_store_cpu(void) 62 + { 63 + struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data); 64 + __cpuinfo_store_cpu(info); 65 + } 66 + 67 + void __init cpuinfo_store_boot_cpu(void) 68 + { 69 + struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0); 70 + __cpuinfo_store_cpu(info); 71 + 72 + boot_cpu_data = *info; 73 + }
+4 -3
arch/arm64/kernel/setup.c
··· 45 45 #include <linux/efi.h> 46 46 47 47 #include <asm/fixmap.h> 48 + #include <asm/cpu.h> 48 49 #include <asm/cputype.h> 49 50 #include <asm/elf.h> 50 51 #include <asm/cputable.h> ··· 219 218 220 219 sprintf(init_utsname()->machine, ELF_PLATFORM); 221 220 elf_hwcap = 0; 221 + 222 + cpuinfo_store_boot_cpu(); 222 223 223 224 /* 224 225 * Check for sane CTR_EL0.CWG value. ··· 420 417 } 421 418 arch_initcall_sync(arm64_device_init); 422 419 423 - static DEFINE_PER_CPU(struct cpu, cpu_data); 424 - 425 420 static int __init topology_init(void) 426 421 { 427 422 int i; 428 423 429 424 for_each_possible_cpu(i) { 430 - struct cpu *cpu = &per_cpu(cpu_data, i); 425 + struct cpu *cpu = &per_cpu(cpu_data.cpu, i); 431 426 cpu->hotpluggable = 1; 432 427 register_cpu(cpu, i); 433 428 }
+6
arch/arm64/kernel/smp.c
··· 39 39 40 40 #include <asm/atomic.h> 41 41 #include <asm/cacheflush.h> 42 + #include <asm/cpu.h> 42 43 #include <asm/cputype.h> 43 44 #include <asm/cpu_ops.h> 44 45 #include <asm/mmu_context.h> ··· 154 153 155 154 if (cpu_ops[cpu]->cpu_postboot) 156 155 cpu_ops[cpu]->cpu_postboot(); 156 + 157 + /* 158 + * Log the CPU info before it is marked online and might get read. 159 + */ 160 + cpuinfo_store_cpu(); 157 161 158 162 /* 159 163 * Enable GIC and timers.