1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/smp.h> 3 #include <linux/timex.h> 4 #include <linux/string.h> 5 #include <linux/seq_file.h> 6 #include <linux/cpufreq.h> 7 8 #include "cpu.h" 9 10 /* 11 * Get CPU information for use by the procfs. 12 */ 13 static void show_cpuinfo_core(struct seq_file *m, struct cpuinfo_x86 *c, 14 unsigned int cpu) 15 { 16 #ifdef CONFIG_SMP 17 seq_printf(m, "physical id\t: %d\n", c->phys_proc_id); 18 seq_printf(m, "siblings\t: %d\n", 19 cpumask_weight(topology_core_cpumask(cpu))); 20 seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id); 21 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores); 22 seq_printf(m, "apicid\t\t: %d\n", c->apicid); 23 seq_printf(m, "initial apicid\t: %d\n", c->initial_apicid); 24 #endif 25 } 26 27 #ifdef CONFIG_X86_32 28 static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c) 29 { 30 seq_printf(m, 31 "fdiv_bug\t: %s\n" 32 "f00f_bug\t: %s\n" 33 "coma_bug\t: %s\n" 34 "fpu\t\t: %s\n" 35 "fpu_exception\t: %s\n" 36 "cpuid level\t: %d\n" 37 "wp\t\t: yes\n", 38 boot_cpu_has_bug(X86_BUG_FDIV) ? "yes" : "no", 39 boot_cpu_has_bug(X86_BUG_F00F) ? "yes" : "no", 40 boot_cpu_has_bug(X86_BUG_COMA) ? "yes" : "no", 41 boot_cpu_has(X86_FEATURE_FPU) ? "yes" : "no", 42 boot_cpu_has(X86_FEATURE_FPU) ? "yes" : "no", 43 c->cpuid_level); 44 } 45 #else 46 static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c) 47 { 48 seq_printf(m, 49 "fpu\t\t: yes\n" 50 "fpu_exception\t: yes\n" 51 "cpuid level\t: %d\n" 52 "wp\t\t: yes\n", 53 c->cpuid_level); 54 } 55 #endif 56 57 static int show_cpuinfo(struct seq_file *m, void *v) 58 { 59 struct cpuinfo_x86 *c = v; 60 unsigned int cpu; 61 int i; 62 63 cpu = c->cpu_index; 64 seq_printf(m, "processor\t: %u\n" 65 "vendor_id\t: %s\n" 66 "cpu family\t: %d\n" 67 "model\t\t: %u\n" 68 "model name\t: %s\n", 69 cpu, 70 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", 71 c->x86, 72 c->x86_model, 73 c->x86_model_id[0] ? c->x86_model_id : "unknown"); 74 75 if (c->x86_stepping || c->cpuid_level >= 0) 76 seq_printf(m, "stepping\t: %d\n", c->x86_stepping); 77 else 78 seq_puts(m, "stepping\t: unknown\n"); 79 if (c->microcode) 80 seq_printf(m, "microcode\t: 0x%x\n", c->microcode); 81 82 if (cpu_has(c, X86_FEATURE_TSC)) { 83 unsigned int freq = aperfmperf_get_khz(cpu); 84 85 if (!freq) 86 freq = cpufreq_quick_get(cpu); 87 if (!freq) 88 freq = cpu_khz; 89 seq_printf(m, "cpu MHz\t\t: %u.%03u\n", 90 freq / 1000, (freq % 1000)); 91 } 92 93 /* Cache size */ 94 if (c->x86_cache_size) 95 seq_printf(m, "cache size\t: %u KB\n", c->x86_cache_size); 96 97 show_cpuinfo_core(m, c, cpu); 98 show_cpuinfo_misc(m, c); 99 100 seq_puts(m, "flags\t\t:"); 101 for (i = 0; i < 32*NCAPINTS; i++) 102 if (cpu_has(c, i) && x86_cap_flags[i] != NULL) 103 seq_printf(m, " %s", x86_cap_flags[i]); 104 105 seq_puts(m, "\nbugs\t\t:"); 106 for (i = 0; i < 32*NBUGINTS; i++) { 107 unsigned int bug_bit = 32*NCAPINTS + i; 108 109 if (cpu_has_bug(c, bug_bit) && x86_bug_flags[i]) 110 seq_printf(m, " %s", x86_bug_flags[i]); 111 } 112 113 seq_printf(m, "\nbogomips\t: %lu.%02lu\n", 114 c->loops_per_jiffy/(500000/HZ), 115 (c->loops_per_jiffy/(5000/HZ)) % 100); 116 117 #ifdef CONFIG_X86_64 118 if (c->x86_tlbsize > 0) 119 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize); 120 #endif 121 seq_printf(m, "clflush size\t: %u\n", c->x86_clflush_size); 122 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment); 123 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", 124 c->x86_phys_bits, c->x86_virt_bits); 125 126 seq_puts(m, "power management:"); 127 for (i = 0; i < 32; i++) { 128 if (c->x86_power & (1 << i)) { 129 if (i < ARRAY_SIZE(x86_power_flags) && 130 x86_power_flags[i]) 131 seq_printf(m, "%s%s", 132 x86_power_flags[i][0] ? " " : "", 133 x86_power_flags[i]); 134 else 135 seq_printf(m, " [%d]", i); 136 } 137 } 138 139 seq_puts(m, "\n\n"); 140 141 return 0; 142 } 143 144 static void *c_start(struct seq_file *m, loff_t *pos) 145 { 146 *pos = cpumask_next(*pos - 1, cpu_online_mask); 147 if ((*pos) < nr_cpu_ids) 148 return &cpu_data(*pos); 149 return NULL; 150 } 151 152 static void *c_next(struct seq_file *m, void *v, loff_t *pos) 153 { 154 (*pos)++; 155 return c_start(m, pos); 156 } 157 158 static void c_stop(struct seq_file *m, void *v) 159 { 160 } 161 162 const struct seq_operations cpuinfo_op = { 163 .start = c_start, 164 .next = c_next, 165 .stop = c_stop, 166 .show = show_cpuinfo, 167 }; 168