1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 1995, 1996, 2001 Ralf Baechle |
4 | * Copyright (C) 2001, 2004 MIPS Technologies, Inc. |
5 | * Copyright (C) 2004 Maciej W. Rozycki |
6 | */ |
7 | #include <linux/delay.h> |
8 | #include <linux/kernel.h> |
9 | #include <linux/sched.h> |
10 | #include <linux/seq_file.h> |
11 | #include <asm/bootinfo.h> |
12 | #include <asm/cpu.h> |
13 | #include <asm/cpu-features.h> |
14 | #include <asm/idle.h> |
15 | #include <asm/mipsregs.h> |
16 | #include <asm/processor.h> |
17 | #include <asm/prom.h> |
18 | |
19 | unsigned int vced_count, vcei_count; |
20 | |
21 | /* |
22 | * No lock; only written during early bootup by CPU 0. |
23 | */ |
24 | static RAW_NOTIFIER_HEAD(proc_cpuinfo_chain); |
25 | |
26 | int __ref register_proc_cpuinfo_notifier(struct notifier_block *nb) |
27 | { |
28 | return raw_notifier_chain_register(nh: &proc_cpuinfo_chain, nb); |
29 | } |
30 | |
31 | int proc_cpuinfo_notifier_call_chain(unsigned long val, void *v) |
32 | { |
33 | return raw_notifier_call_chain(nh: &proc_cpuinfo_chain, val, v); |
34 | } |
35 | |
36 | static int show_cpuinfo(struct seq_file *m, void *v) |
37 | { |
38 | struct proc_cpuinfo_notifier_args proc_cpuinfo_notifier_args; |
39 | unsigned long n = (unsigned long) v - 1; |
40 | unsigned int version = cpu_data[n].processor_id; |
41 | unsigned int fp_vers = cpu_data[n].fpu_id; |
42 | char fmt[64]; |
43 | int i; |
44 | |
45 | #ifdef CONFIG_SMP |
46 | if (!cpu_online(cpu: n)) |
47 | return 0; |
48 | #endif |
49 | |
50 | /* |
51 | * For the first processor also print the system type |
52 | */ |
53 | if (n == 0) { |
54 | seq_printf(m, fmt: "system type\t\t: %s\n" , get_system_type()); |
55 | if (mips_get_machine_name()) |
56 | seq_printf(m, fmt: "machine\t\t\t: %s\n" , |
57 | mips_get_machine_name()); |
58 | } |
59 | |
60 | seq_printf(m, fmt: "processor\t\t: %ld\n" , n); |
61 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n" , |
62 | cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : "" ); |
63 | seq_printf(m, fmt, __cpu_name[n], |
64 | (version >> 4) & 0x0f, version & 0x0f, |
65 | (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); |
66 | seq_printf(m, "BogoMIPS\t\t: %u.%02u\n" , |
67 | cpu_data[n].udelay_val / (500000/HZ), |
68 | (cpu_data[n].udelay_val / (5000/HZ)) % 100); |
69 | seq_printf(m, fmt: "wait instruction\t: %s\n" , cpu_wait ? "yes" : "no" ); |
70 | seq_printf(m, fmt: "microsecond timers\t: %s\n" , |
71 | cpu_has_counter ? "yes" : "no" ); |
72 | seq_printf(m, "tlb_entries\t\t: %d\n" , cpu_data[n].tlbsize); |
73 | seq_printf(m, fmt: "extra interrupt vector\t: %s\n" , |
74 | cpu_has_divec ? "yes" : "no" ); |
75 | seq_printf(m, fmt: "hardware watchpoint\t: %s" , |
76 | cpu_has_watch ? "yes, " : "no\n" ); |
77 | if (cpu_has_watch) { |
78 | seq_printf(m, "count: %d, address/irw mask: [" , |
79 | cpu_data[n].watch_reg_count); |
80 | for (i = 0; i < cpu_data[n].watch_reg_count; i++) |
81 | seq_printf(m, "%s0x%04x" , i ? ", " : "" , |
82 | cpu_data[n].watch_reg_masks[i]); |
83 | seq_puts(m, s: "]\n" ); |
84 | } |
85 | |
86 | seq_puts(m, s: "isa\t\t\t:" ); |
87 | if (cpu_has_mips_1) |
88 | seq_puts(m, s: " mips1" ); |
89 | if (cpu_has_mips_2) |
90 | seq_puts(m, s: " mips2" ); |
91 | if (cpu_has_mips_3) |
92 | seq_puts(m, s: " mips3" ); |
93 | if (cpu_has_mips_4) |
94 | seq_puts(m, s: " mips4" ); |
95 | if (cpu_has_mips_5) |
96 | seq_puts(m, s: " mips5" ); |
97 | if (cpu_has_mips32r1) |
98 | seq_puts(m, s: " mips32r1" ); |
99 | if (cpu_has_mips32r2) |
100 | seq_puts(m, s: " mips32r2" ); |
101 | if (cpu_has_mips32r5) |
102 | seq_puts(m, s: " mips32r5" ); |
103 | if (cpu_has_mips32r6) |
104 | seq_puts(m, s: " mips32r6" ); |
105 | if (cpu_has_mips64r1) |
106 | seq_puts(m, s: " mips64r1" ); |
107 | if (cpu_has_mips64r2) |
108 | seq_puts(m, s: " mips64r2" ); |
109 | if (cpu_has_mips64r5) |
110 | seq_puts(m, s: " mips64r5" ); |
111 | if (cpu_has_mips64r6) |
112 | seq_puts(m, s: " mips64r6" ); |
113 | seq_puts(m, s: "\n" ); |
114 | |
115 | seq_puts(m, s: "ASEs implemented\t:" ); |
116 | if (cpu_has_mips16) |
117 | seq_puts(m, s: " mips16" ); |
118 | if (cpu_has_mips16e2) |
119 | seq_puts(m, s: " mips16e2" ); |
120 | if (cpu_has_mdmx) |
121 | seq_puts(m, s: " mdmx" ); |
122 | if (cpu_has_mips3d) |
123 | seq_puts(m, s: " mips3d" ); |
124 | if (cpu_has_smartmips) |
125 | seq_puts(m, s: " smartmips" ); |
126 | if (cpu_has_dsp) |
127 | seq_puts(m, s: " dsp" ); |
128 | if (cpu_has_dsp2) |
129 | seq_puts(m, s: " dsp2" ); |
130 | if (cpu_has_dsp3) |
131 | seq_puts(m, s: " dsp3" ); |
132 | if (cpu_has_mipsmt) |
133 | seq_puts(m, s: " mt" ); |
134 | if (cpu_has_mmips) |
135 | seq_puts(m, s: " micromips" ); |
136 | if (cpu_has_vz) |
137 | seq_puts(m, s: " vz" ); |
138 | if (cpu_has_msa) |
139 | seq_puts(m, s: " msa" ); |
140 | if (cpu_has_eva) |
141 | seq_puts(m, s: " eva" ); |
142 | if (cpu_has_htw) |
143 | seq_puts(m, s: " htw" ); |
144 | if (cpu_has_xpa) |
145 | seq_puts(m, s: " xpa" ); |
146 | if (cpu_has_loongson_mmi) |
147 | seq_puts(m, s: " loongson-mmi" ); |
148 | if (cpu_has_loongson_cam) |
149 | seq_puts(m, s: " loongson-cam" ); |
150 | if (cpu_has_loongson_ext) |
151 | seq_puts(m, s: " loongson-ext" ); |
152 | if (cpu_has_loongson_ext2) |
153 | seq_puts(m, s: " loongson-ext2" ); |
154 | seq_puts(m, s: "\n" ); |
155 | |
156 | if (cpu_has_mmips) { |
157 | seq_printf(m, "micromips kernel\t: %s\n" , |
158 | (read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no" ); |
159 | } |
160 | |
161 | seq_puts(m, s: "Options implemented\t:" ); |
162 | if (cpu_has_tlb) |
163 | seq_puts(m, s: " tlb" ); |
164 | if (cpu_has_ftlb) |
165 | seq_puts(m, s: " ftlb" ); |
166 | if (cpu_has_tlbinv) |
167 | seq_puts(m, s: " tlbinv" ); |
168 | if (cpu_has_segments) |
169 | seq_puts(m, s: " segments" ); |
170 | if (cpu_has_rixiex) |
171 | seq_puts(m, s: " rixiex" ); |
172 | if (cpu_has_ldpte) |
173 | seq_puts(m, s: " ldpte" ); |
174 | if (cpu_has_maar) |
175 | seq_puts(m, s: " maar" ); |
176 | if (cpu_has_rw_llb) |
177 | seq_puts(m, s: " rw_llb" ); |
178 | if (cpu_has_4kex) |
179 | seq_puts(m, s: " 4kex" ); |
180 | if (cpu_has_3k_cache) |
181 | seq_puts(m, s: " 3k_cache" ); |
182 | if (cpu_has_4k_cache) |
183 | seq_puts(m, s: " 4k_cache" ); |
184 | if (cpu_has_octeon_cache) |
185 | seq_puts(m, s: " octeon_cache" ); |
186 | if (raw_cpu_has_fpu) |
187 | seq_puts(m, s: " fpu" ); |
188 | if (cpu_has_32fpr) |
189 | seq_puts(m, s: " 32fpr" ); |
190 | if (cpu_has_cache_cdex_p) |
191 | seq_puts(m, s: " cache_cdex_p" ); |
192 | if (cpu_has_cache_cdex_s) |
193 | seq_puts(m, s: " cache_cdex_s" ); |
194 | if (cpu_has_prefetch) |
195 | seq_puts(m, s: " prefetch" ); |
196 | if (cpu_has_mcheck) |
197 | seq_puts(m, s: " mcheck" ); |
198 | if (cpu_has_ejtag) |
199 | seq_puts(m, s: " ejtag" ); |
200 | if (cpu_has_llsc) |
201 | seq_puts(m, s: " llsc" ); |
202 | if (cpu_has_guestctl0ext) |
203 | seq_puts(m, s: " guestctl0ext" ); |
204 | if (cpu_has_guestctl1) |
205 | seq_puts(m, s: " guestctl1" ); |
206 | if (cpu_has_guestctl2) |
207 | seq_puts(m, s: " guestctl2" ); |
208 | if (cpu_has_guestid) |
209 | seq_puts(m, s: " guestid" ); |
210 | if (cpu_has_drg) |
211 | seq_puts(m, s: " drg" ); |
212 | if (cpu_has_rixi) |
213 | seq_puts(m, s: " rixi" ); |
214 | if (cpu_has_lpa) |
215 | seq_puts(m, s: " lpa" ); |
216 | if (cpu_has_mvh) |
217 | seq_puts(m, s: " mvh" ); |
218 | if (cpu_has_vtag_icache) |
219 | seq_puts(m, s: " vtag_icache" ); |
220 | if (cpu_has_dc_aliases) |
221 | seq_puts(m, s: " dc_aliases" ); |
222 | if (cpu_has_ic_fills_f_dc) |
223 | seq_puts(m, s: " ic_fills_f_dc" ); |
224 | if (cpu_has_pindexed_dcache) |
225 | seq_puts(m, s: " pindexed_dcache" ); |
226 | if (cpu_has_userlocal) |
227 | seq_puts(m, s: " userlocal" ); |
228 | if (cpu_has_nofpuex) |
229 | seq_puts(m, s: " nofpuex" ); |
230 | if (cpu_has_vint) |
231 | seq_puts(m, s: " vint" ); |
232 | if (cpu_has_veic) |
233 | seq_puts(m, s: " veic" ); |
234 | if (cpu_has_inclusive_pcaches) |
235 | seq_puts(m, s: " inclusive_pcaches" ); |
236 | if (cpu_has_perf_cntr_intr_bit) |
237 | seq_puts(m, s: " perf_cntr_intr_bit" ); |
238 | if (cpu_has_ufr) |
239 | seq_puts(m, s: " ufr" ); |
240 | if (cpu_has_fre) |
241 | seq_puts(m, s: " fre" ); |
242 | if (cpu_has_cdmm) |
243 | seq_puts(m, s: " cdmm" ); |
244 | if (cpu_has_small_pages) |
245 | seq_puts(m, s: " small_pages" ); |
246 | if (cpu_has_nan_legacy) |
247 | seq_puts(m, s: " nan_legacy" ); |
248 | if (cpu_has_nan_2008) |
249 | seq_puts(m, s: " nan_2008" ); |
250 | if (cpu_has_ebase_wg) |
251 | seq_puts(m, s: " ebase_wg" ); |
252 | if (cpu_has_badinstr) |
253 | seq_puts(m, s: " badinstr" ); |
254 | if (cpu_has_badinstrp) |
255 | seq_puts(m, s: " badinstrp" ); |
256 | if (cpu_has_contextconfig) |
257 | seq_puts(m, s: " contextconfig" ); |
258 | if (cpu_has_perf) |
259 | seq_puts(m, s: " perf" ); |
260 | if (cpu_has_mac2008_only) |
261 | seq_puts(m, s: " mac2008_only" ); |
262 | if (cpu_has_ftlbparex) |
263 | seq_puts(m, s: " ftlbparex" ); |
264 | if (cpu_has_gsexcex) |
265 | seq_puts(m, s: " gsexcex" ); |
266 | if (cpu_has_shared_ftlb_ram) |
267 | seq_puts(m, s: " shared_ftlb_ram" ); |
268 | if (cpu_has_shared_ftlb_entries) |
269 | seq_puts(m, s: " shared_ftlb_entries" ); |
270 | if (cpu_has_mipsmt_pertccounters) |
271 | seq_puts(m, s: " mipsmt_pertccounters" ); |
272 | if (cpu_has_mmid) |
273 | seq_puts(m, s: " mmid" ); |
274 | if (cpu_has_mm_sysad) |
275 | seq_puts(m, s: " mm_sysad" ); |
276 | if (cpu_has_mm_full) |
277 | seq_puts(m, s: " mm_full" ); |
278 | seq_puts(m, s: "\n" ); |
279 | |
280 | seq_printf(m, "shadow register sets\t: %d\n" , |
281 | cpu_data[n].srsets); |
282 | seq_printf(m, "kscratch registers\t: %d\n" , |
283 | hweight8(cpu_data[n].kscratch_mask)); |
284 | seq_printf(m, "package\t\t\t: %d\n" , cpu_data[n].package); |
285 | seq_printf(m, "core\t\t\t: %d\n" , cpu_core(&cpu_data[n])); |
286 | |
287 | #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) |
288 | if (cpu_has_mipsmt) |
289 | seq_printf(m, "VPE\t\t\t: %d\n" , cpu_vpe_id(&cpu_data[n])); |
290 | else if (cpu_has_vp) |
291 | seq_printf(m, "VP\t\t\t: %d\n" , cpu_vpe_id(&cpu_data[n])); |
292 | #endif |
293 | |
294 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n" , |
295 | cpu_has_vce ? "%u" : "not available" ); |
296 | seq_printf(m, fmt, 'D', vced_count); |
297 | seq_printf(m, fmt, 'I', vcei_count); |
298 | |
299 | proc_cpuinfo_notifier_args.m = m; |
300 | proc_cpuinfo_notifier_args.n = n; |
301 | |
302 | raw_notifier_call_chain(nh: &proc_cpuinfo_chain, val: 0, |
303 | v: &proc_cpuinfo_notifier_args); |
304 | |
305 | seq_puts(m, s: "\n" ); |
306 | |
307 | return 0; |
308 | } |
309 | |
310 | static void *c_start(struct seq_file *m, loff_t *pos) |
311 | { |
312 | unsigned long i = *pos; |
313 | |
314 | return i < nr_cpu_ids ? (void *) (i + 1) : NULL; |
315 | } |
316 | |
317 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) |
318 | { |
319 | ++*pos; |
320 | return c_start(m, pos); |
321 | } |
322 | |
323 | static void c_stop(struct seq_file *m, void *v) |
324 | { |
325 | } |
326 | |
327 | const struct seq_operations cpuinfo_op = { |
328 | .start = c_start, |
329 | .next = c_next, |
330 | .stop = c_stop, |
331 | .show = show_cpuinfo, |
332 | }; |
333 | |