xref: /openbmc/linux/arch/s390/kernel/processor.c (revision 79ab11cd)
1395d31d4SMartin Schwidefsky /*
2395d31d4SMartin Schwidefsky  *  Copyright IBM Corp. 2008
3395d31d4SMartin Schwidefsky  *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
4395d31d4SMartin Schwidefsky  */
5395d31d4SMartin Schwidefsky 
6395d31d4SMartin Schwidefsky #define KMSG_COMPONENT "cpu"
7395d31d4SMartin Schwidefsky #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
8395d31d4SMartin Schwidefsky 
9ca21872eSHeiko Carstens #include <linux/cpufeature.h>
10395d31d4SMartin Schwidefsky #include <linux/kernel.h>
11395d31d4SMartin Schwidefsky #include <linux/init.h>
12395d31d4SMartin Schwidefsky #include <linux/seq_file.h>
13395d31d4SMartin Schwidefsky #include <linux/delay.h>
1419726cecSHeiko Carstens #include <linux/cpu.h>
151ec2772eSMartin Schwidefsky #include <asm/diag.h>
16097a116cSHeiko Carstens #include <asm/facility.h>
17395d31d4SMartin Schwidefsky #include <asm/elf.h>
18395d31d4SMartin Schwidefsky #include <asm/lowcore.h>
19395d31d4SMartin Schwidefsky #include <asm/param.h>
204d92f502SHeiko Carstens #include <asm/smp.h>
21395d31d4SMartin Schwidefsky 
22097a116cSHeiko Carstens struct cpu_info {
23097a116cSHeiko Carstens 	unsigned int cpu_mhz_dynamic;
24097a116cSHeiko Carstens 	unsigned int cpu_mhz_static;
25097a116cSHeiko Carstens 	struct cpuid cpu_id;
26097a116cSHeiko Carstens };
27097a116cSHeiko Carstens 
28097a116cSHeiko Carstens static DEFINE_PER_CPU(struct cpu_info, cpu_info);
29097a116cSHeiko Carstens 
30097a116cSHeiko Carstens static bool machine_has_cpu_mhz;
31097a116cSHeiko Carstens 
32097a116cSHeiko Carstens void __init cpu_detect_mhz_feature(void)
33097a116cSHeiko Carstens {
34097a116cSHeiko Carstens 	if (test_facility(34) && __ecag(ECAG_CPU_ATTRIBUTE, 0) != -1UL)
35097a116cSHeiko Carstens 		machine_has_cpu_mhz = 1;
36097a116cSHeiko Carstens }
37097a116cSHeiko Carstens 
38097a116cSHeiko Carstens static void update_cpu_mhz(void *arg)
39097a116cSHeiko Carstens {
40097a116cSHeiko Carstens 	unsigned long mhz;
41097a116cSHeiko Carstens 	struct cpu_info *c;
42097a116cSHeiko Carstens 
43097a116cSHeiko Carstens 	mhz = __ecag(ECAG_CPU_ATTRIBUTE, 0);
44097a116cSHeiko Carstens 	c = this_cpu_ptr(&cpu_info);
45097a116cSHeiko Carstens 	c->cpu_mhz_dynamic = mhz >> 32;
46097a116cSHeiko Carstens 	c->cpu_mhz_static = mhz & 0xffffffff;
47097a116cSHeiko Carstens }
48097a116cSHeiko Carstens 
49097a116cSHeiko Carstens void s390_update_cpu_mhz(void)
50097a116cSHeiko Carstens {
51097a116cSHeiko Carstens 	s390_adjust_jiffies();
52097a116cSHeiko Carstens 	if (machine_has_cpu_mhz)
53097a116cSHeiko Carstens 		on_each_cpu(update_cpu_mhz, NULL, 0);
54097a116cSHeiko Carstens }
5594038a99SMartin Schwidefsky 
5679ab11cdSChristian Borntraeger void notrace cpu_relax_yield(void)
574d92f502SHeiko Carstens {
581ec2772eSMartin Schwidefsky 	if (!smp_cpu_mtid && MACHINE_HAS_DIAG44) {
591ec2772eSMartin Schwidefsky 		diag_stat_inc(DIAG_STAT_X044);
604d92f502SHeiko Carstens 		asm volatile("diag 0,0,0x44");
611ec2772eSMartin Schwidefsky 	}
624d92f502SHeiko Carstens 	barrier();
634d92f502SHeiko Carstens }
6479ab11cdSChristian Borntraeger EXPORT_SYMBOL(cpu_relax_yield);
654d92f502SHeiko Carstens 
6694038a99SMartin Schwidefsky /*
6794038a99SMartin Schwidefsky  * cpu_init - initializes state that is per-CPU.
6894038a99SMartin Schwidefsky  */
69e2741f17SPaul Gortmaker void cpu_init(void)
7094038a99SMartin Schwidefsky {
71097a116cSHeiko Carstens 	struct cpuid *id = this_cpu_ptr(&cpu_info.cpu_id);
7294038a99SMartin Schwidefsky 
7394038a99SMartin Schwidefsky 	get_cpu_id(id);
74097a116cSHeiko Carstens 	if (machine_has_cpu_mhz)
75097a116cSHeiko Carstens 		update_cpu_mhz(NULL);
7694038a99SMartin Schwidefsky 	atomic_inc(&init_mm.mm_count);
7794038a99SMartin Schwidefsky 	current->active_mm = &init_mm;
7894038a99SMartin Schwidefsky 	BUG_ON(current->mm);
7994038a99SMartin Schwidefsky 	enter_lazy_tlb(&init_mm, current);
8094038a99SMartin Schwidefsky }
8194038a99SMartin Schwidefsky 
8294038a99SMartin Schwidefsky /*
838f00b3e2SHendrik Brueckner  * cpu_have_feature - Test CPU features on module initialization
848f00b3e2SHendrik Brueckner  */
858f00b3e2SHendrik Brueckner int cpu_have_feature(unsigned int num)
868f00b3e2SHendrik Brueckner {
878f00b3e2SHendrik Brueckner 	return elf_hwcap & (1UL << num);
888f00b3e2SHendrik Brueckner }
898f00b3e2SHendrik Brueckner EXPORT_SYMBOL(cpu_have_feature);
908f00b3e2SHendrik Brueckner 
91219a21b3SHeiko Carstens static void show_cpu_summary(struct seq_file *m, void *v)
92395d31d4SMartin Schwidefsky {
93fbf3c542SHeiko Carstens 	static const char *hwcap_str[] = {
94395d31d4SMartin Schwidefsky 		"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
9580703617SMartin Schwidefsky 		"edat", "etf3eh", "highgprs", "te", "vx"
96395d31d4SMartin Schwidefsky 	};
977f16d7e7SDavid Hildenbrand 	static const char * const int_hwcap_str[] = {
987f16d7e7SDavid Hildenbrand 		"sie"
997f16d7e7SDavid Hildenbrand 	};
100219a21b3SHeiko Carstens 	int i, cpu;
101395d31d4SMartin Schwidefsky 
102395d31d4SMartin Schwidefsky 	seq_printf(m, "vendor_id       : IBM/S390\n"
103395d31d4SMartin Schwidefsky 		   "# processors    : %i\n"
104395d31d4SMartin Schwidefsky 		   "bogomips per cpu: %lu.%02lu\n",
105395d31d4SMartin Schwidefsky 		   num_online_cpus(), loops_per_jiffy/(500000/HZ),
106395d31d4SMartin Schwidefsky 		   (loops_per_jiffy/(5000/HZ))%100);
10710f4954aSHeiko Carstens 	seq_printf(m, "max thread id   : %d\n", smp_cpu_mtid);
108395d31d4SMartin Schwidefsky 	seq_puts(m, "features\t: ");
109fbf3c542SHeiko Carstens 	for (i = 0; i < ARRAY_SIZE(hwcap_str); i++)
110395d31d4SMartin Schwidefsky 		if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
111395d31d4SMartin Schwidefsky 			seq_printf(m, "%s ", hwcap_str[i]);
1127f16d7e7SDavid Hildenbrand 	for (i = 0; i < ARRAY_SIZE(int_hwcap_str); i++)
1137f16d7e7SDavid Hildenbrand 		if (int_hwcap_str[i] && (int_hwcap & (1UL << i)))
1147f16d7e7SDavid Hildenbrand 			seq_printf(m, "%s ", int_hwcap_str[i]);
115395d31d4SMartin Schwidefsky 	seq_puts(m, "\n");
1166668022cSHeiko Carstens 	show_cacheinfo(m);
117219a21b3SHeiko Carstens 	for_each_online_cpu(cpu) {
118097a116cSHeiko Carstens 		struct cpuid *id = &per_cpu(cpu_info.cpu_id, cpu);
119219a21b3SHeiko Carstens 
120219a21b3SHeiko Carstens 		seq_printf(m, "processor %d: "
121395d31d4SMartin Schwidefsky 			   "version = %02X,  "
122395d31d4SMartin Schwidefsky 			   "identification = %06X,  "
123395d31d4SMartin Schwidefsky 			   "machine = %04X\n",
124219a21b3SHeiko Carstens 			   cpu, id->version, id->ident, id->machine);
125395d31d4SMartin Schwidefsky 	}
126219a21b3SHeiko Carstens }
127219a21b3SHeiko Carstens 
128097a116cSHeiko Carstens static void show_cpu_mhz(struct seq_file *m, unsigned long n)
129097a116cSHeiko Carstens {
130097a116cSHeiko Carstens 	struct cpu_info *c = per_cpu_ptr(&cpu_info, n);
131097a116cSHeiko Carstens 
132097a116cSHeiko Carstens 	seq_printf(m, "cpu MHz dynamic : %d\n", c->cpu_mhz_dynamic);
133097a116cSHeiko Carstens 	seq_printf(m, "cpu MHz static  : %d\n", c->cpu_mhz_static);
134097a116cSHeiko Carstens }
135097a116cSHeiko Carstens 
136219a21b3SHeiko Carstens /*
137219a21b3SHeiko Carstens  * show_cpuinfo - Get information on one CPU for use by procfs.
138219a21b3SHeiko Carstens  */
139219a21b3SHeiko Carstens static int show_cpuinfo(struct seq_file *m, void *v)
140219a21b3SHeiko Carstens {
141219a21b3SHeiko Carstens 	unsigned long n = (unsigned long) v - 1;
142219a21b3SHeiko Carstens 
143219a21b3SHeiko Carstens 	if (!n)
144219a21b3SHeiko Carstens 		show_cpu_summary(m, v);
145097a116cSHeiko Carstens 	if (!machine_has_cpu_mhz)
146097a116cSHeiko Carstens 		return 0;
147109ab954SHeiko Carstens 	seq_printf(m, "\ncpu number      : %ld\n", n);
148097a116cSHeiko Carstens 	show_cpu_mhz(m, n);
149395d31d4SMartin Schwidefsky 	return 0;
150395d31d4SMartin Schwidefsky }
151395d31d4SMartin Schwidefsky 
152281eaa8cSHeiko Carstens static inline void *c_update(loff_t *pos)
153281eaa8cSHeiko Carstens {
154281eaa8cSHeiko Carstens 	if (*pos)
155281eaa8cSHeiko Carstens 		*pos = cpumask_next(*pos - 1, cpu_online_mask);
156281eaa8cSHeiko Carstens 	return *pos < nr_cpu_ids ? (void *)*pos + 1 : NULL;
157281eaa8cSHeiko Carstens }
158281eaa8cSHeiko Carstens 
159395d31d4SMartin Schwidefsky static void *c_start(struct seq_file *m, loff_t *pos)
160395d31d4SMartin Schwidefsky {
161281eaa8cSHeiko Carstens 	get_online_cpus();
162281eaa8cSHeiko Carstens 	return c_update(pos);
163395d31d4SMartin Schwidefsky }
164395d31d4SMartin Schwidefsky 
165395d31d4SMartin Schwidefsky static void *c_next(struct seq_file *m, void *v, loff_t *pos)
166395d31d4SMartin Schwidefsky {
167395d31d4SMartin Schwidefsky 	++*pos;
168281eaa8cSHeiko Carstens 	return c_update(pos);
169395d31d4SMartin Schwidefsky }
170395d31d4SMartin Schwidefsky 
171395d31d4SMartin Schwidefsky static void c_stop(struct seq_file *m, void *v)
172395d31d4SMartin Schwidefsky {
173281eaa8cSHeiko Carstens 	put_online_cpus();
174395d31d4SMartin Schwidefsky }
175395d31d4SMartin Schwidefsky 
176395d31d4SMartin Schwidefsky const struct seq_operations cpuinfo_op = {
177395d31d4SMartin Schwidefsky 	.start	= c_start,
178395d31d4SMartin Schwidefsky 	.next	= c_next,
179395d31d4SMartin Schwidefsky 	.stop	= c_stop,
180395d31d4SMartin Schwidefsky 	.show	= show_cpuinfo,
181395d31d4SMartin Schwidefsky };
182