1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/seq_file.h> |
3 | #include <linux/kernel.h> |
4 | #include <linux/module.h> |
5 | #include <asm/machvec.h> |
6 | #include <asm/processor.h> |
7 | |
8 | static const char *cpu_name[] = { |
9 | [CPU_SH7201] = "SH7201" , |
10 | [CPU_SH7203] = "SH7203" , [CPU_SH7263] = "SH7263" , |
11 | [CPU_SH7264] = "SH7264" , [CPU_SH7269] = "SH7269" , |
12 | [CPU_SH7206] = "SH7206" , [CPU_SH7619] = "SH7619" , |
13 | [CPU_SH7705] = "SH7705" , [CPU_SH7706] = "SH7706" , |
14 | [CPU_SH7707] = "SH7707" , [CPU_SH7708] = "SH7708" , |
15 | [CPU_SH7709] = "SH7709" , [CPU_SH7710] = "SH7710" , |
16 | [CPU_SH7712] = "SH7712" , [CPU_SH7720] = "SH7720" , |
17 | [CPU_SH7721] = "SH7721" , [CPU_SH7729] = "SH7729" , |
18 | [CPU_SH7750] = "SH7750" , [CPU_SH7750S] = "SH7750S" , |
19 | [CPU_SH7750R] = "SH7750R" , [CPU_SH7751] = "SH7751" , |
20 | [CPU_SH7751R] = "SH7751R" , [CPU_SH7760] = "SH7760" , |
21 | [CPU_SH4_202] = "SH4-202" , [CPU_SH4_501] = "SH4-501" , |
22 | [CPU_SH7763] = "SH7763" , [CPU_SH7770] = "SH7770" , |
23 | [CPU_SH7780] = "SH7780" , [CPU_SH7781] = "SH7781" , |
24 | [CPU_SH7343] = "SH7343" , [CPU_SH7785] = "SH7785" , |
25 | [CPU_SH7786] = "SH7786" , [CPU_SH7757] = "SH7757" , |
26 | [CPU_SH7722] = "SH7722" , [CPU_SHX3] = "SH-X3" , |
27 | [CPU_MXG] = "MX-G" , [CPU_SH7723] = "SH7723" , |
28 | [CPU_SH7366] = "SH7366" , [CPU_SH7724] = "SH7724" , |
29 | [CPU_SH7372] = "SH7372" , [CPU_SH7734] = "SH7734" , |
30 | [CPU_J2] = "J2" , |
31 | [CPU_SH_NONE] = "Unknown" |
32 | }; |
33 | |
34 | const char *get_cpu_subtype(struct sh_cpuinfo *c) |
35 | { |
36 | return cpu_name[c->type]; |
37 | } |
38 | EXPORT_SYMBOL(get_cpu_subtype); |
39 | |
40 | #ifdef CONFIG_PROC_FS |
41 | /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */ |
42 | static const char *cpu_flags[] = { |
43 | "none" , "fpu" , "p2flush" , "mmuassoc" , "dsp" , "perfctr" , |
44 | "ptea" , "llsc" , "l2" , "op32" , "pteaex" , NULL |
45 | }; |
46 | |
47 | static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c) |
48 | { |
49 | unsigned long i; |
50 | |
51 | seq_printf(m, fmt: "cpu flags\t:" ); |
52 | |
53 | if (!c->flags) { |
54 | seq_printf(m, fmt: " %s\n" , cpu_flags[0]); |
55 | return; |
56 | } |
57 | |
58 | for (i = 0; cpu_flags[i]; i++) |
59 | if ((c->flags & (1 << i))) |
60 | seq_printf(m, fmt: " %s" , cpu_flags[i+1]); |
61 | |
62 | seq_printf(m, fmt: "\n" ); |
63 | } |
64 | |
65 | static void show_cacheinfo(struct seq_file *m, const char *type, |
66 | struct cache_info info) |
67 | { |
68 | unsigned int cache_size; |
69 | |
70 | cache_size = info.ways * info.sets * info.linesz; |
71 | |
72 | seq_printf(m, fmt: "%s size\t: %2dKiB (%d-way)\n" , |
73 | type, cache_size >> 10, info.ways); |
74 | } |
75 | |
76 | /* |
77 | * Get CPU information for use by the procfs. |
78 | */ |
79 | static int show_cpuinfo(struct seq_file *m, void *v) |
80 | { |
81 | struct sh_cpuinfo *c = v; |
82 | unsigned int cpu = c - cpu_data; |
83 | |
84 | if (!cpu_online(cpu)) |
85 | return 0; |
86 | |
87 | if (cpu == 0) |
88 | seq_printf(m, fmt: "machine\t\t: %s\n" , get_system_type()); |
89 | else |
90 | seq_printf(m, fmt: "\n" ); |
91 | |
92 | seq_printf(m, fmt: "processor\t: %d\n" , cpu); |
93 | seq_printf(m, fmt: "cpu family\t: %s\n" , init_utsname()->machine); |
94 | seq_printf(m, fmt: "cpu type\t: %s\n" , get_cpu_subtype(c)); |
95 | if (c->cut_major == -1) |
96 | seq_printf(m, fmt: "cut\t\t: unknown\n" ); |
97 | else if (c->cut_minor == -1) |
98 | seq_printf(m, fmt: "cut\t\t: %d.x\n" , c->cut_major); |
99 | else |
100 | seq_printf(m, fmt: "cut\t\t: %d.%d\n" , c->cut_major, c->cut_minor); |
101 | |
102 | show_cpuflags(m, c); |
103 | |
104 | seq_printf(m, fmt: "cache type\t: " ); |
105 | |
106 | /* |
107 | * Check for what type of cache we have, we support both the |
108 | * unified cache on the SH-2 and SH-3, as well as the harvard |
109 | * style cache on the SH-4. |
110 | */ |
111 | if (c->icache.flags & SH_CACHE_COMBINED) { |
112 | seq_printf(m, fmt: "unified\n" ); |
113 | show_cacheinfo(m, type: "cache" , info: c->icache); |
114 | } else { |
115 | seq_printf(m, fmt: "split (harvard)\n" ); |
116 | show_cacheinfo(m, type: "icache" , info: c->icache); |
117 | show_cacheinfo(m, type: "dcache" , info: c->dcache); |
118 | } |
119 | |
120 | /* Optional secondary cache */ |
121 | if (c->flags & CPU_HAS_L2_CACHE) |
122 | show_cacheinfo(m, type: "scache" , info: c->scache); |
123 | |
124 | seq_printf(m, fmt: "address sizes\t: %u bits physical\n" , c->phys_bits); |
125 | |
126 | seq_printf(m, fmt: "bogomips\t: %lu.%02lu\n" , |
127 | c->loops_per_jiffy/(500000/HZ), |
128 | (c->loops_per_jiffy/(5000/HZ)) % 100); |
129 | |
130 | return 0; |
131 | } |
132 | |
133 | static void *c_start(struct seq_file *m, loff_t *pos) |
134 | { |
135 | return *pos < NR_CPUS ? cpu_data + *pos : NULL; |
136 | } |
137 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) |
138 | { |
139 | ++*pos; |
140 | return c_start(m, pos); |
141 | } |
142 | static void c_stop(struct seq_file *m, void *v) |
143 | { |
144 | } |
145 | const struct seq_operations cpuinfo_op = { |
146 | .start = c_start, |
147 | .next = c_next, |
148 | .stop = c_stop, |
149 | .show = show_cpuinfo, |
150 | }; |
151 | #endif /* CONFIG_PROC_FS */ |
152 | |