1 // SPDX-License-Identifier: GPL-2.0
3 * Idle functions for s390.
5 * Copyright IBM Corp. 2014
7 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
10 #include <linux/kernel.h>
11 #include <linux/kernel_stat.h>
12 #include <linux/kprobes.h>
13 #include <linux/notifier.h>
14 #include <linux/init.h>
15 #include <linux/cpu.h>
16 #include <linux/sched/cputime.h>
21 static DEFINE_PER_CPU(struct s390_idle_data
, s390_idle
);
23 void enabled_wait(void)
25 struct s390_idle_data
*idle
= this_cpu_ptr(&s390_idle
);
26 unsigned long long idle_time
;
27 unsigned long psw_mask
;
31 /* Wait for external, I/O or machine check interrupt. */
32 psw_mask
= PSW_KERNEL_BITS
| PSW_MASK_WAIT
| PSW_MASK_DAT
|
33 PSW_MASK_IO
| PSW_MASK_EXT
| PSW_MASK_MCHECK
;
34 clear_cpu_flag(CIF_NOHZ_DELAY
);
36 /* Call the assembler magic in entry.S */
37 psw_idle(idle
, psw_mask
);
41 /* Account time spent with enabled wait psw loaded as idle time. */
42 write_seqcount_begin(&idle
->seqcount
);
43 idle_time
= idle
->clock_idle_exit
- idle
->clock_idle_enter
;
44 idle
->clock_idle_enter
= idle
->clock_idle_exit
= 0ULL;
45 idle
->idle_time
+= idle_time
;
47 account_idle_time(cputime_to_nsecs(idle_time
));
48 write_seqcount_end(&idle
->seqcount
);
50 NOKPROBE_SYMBOL(enabled_wait
);
52 static ssize_t
show_idle_count(struct device
*dev
,
53 struct device_attribute
*attr
, char *buf
)
55 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, dev
->id
);
56 unsigned long long idle_count
;
60 seq
= read_seqcount_begin(&idle
->seqcount
);
61 idle_count
= READ_ONCE(idle
->idle_count
);
62 if (READ_ONCE(idle
->clock_idle_enter
))
64 } while (read_seqcount_retry(&idle
->seqcount
, seq
));
65 return sprintf(buf
, "%llu\n", idle_count
);
67 DEVICE_ATTR(idle_count
, 0444, show_idle_count
, NULL
);
69 static ssize_t
show_idle_time(struct device
*dev
,
70 struct device_attribute
*attr
, char *buf
)
72 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, dev
->id
);
73 unsigned long long now
, idle_time
, idle_enter
, idle_exit
;
77 now
= get_tod_clock();
78 seq
= read_seqcount_begin(&idle
->seqcount
);
79 idle_time
= READ_ONCE(idle
->idle_time
);
80 idle_enter
= READ_ONCE(idle
->clock_idle_enter
);
81 idle_exit
= READ_ONCE(idle
->clock_idle_exit
);
82 } while (read_seqcount_retry(&idle
->seqcount
, seq
));
83 idle_time
+= idle_enter
? ((idle_exit
? : now
) - idle_enter
) : 0;
84 return sprintf(buf
, "%llu\n", idle_time
>> 12);
86 DEVICE_ATTR(idle_time_us
, 0444, show_idle_time
, NULL
);
88 u64
arch_cpu_idle_time(int cpu
)
90 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, cpu
);
91 unsigned long long now
, idle_enter
, idle_exit
;
95 now
= get_tod_clock();
96 seq
= read_seqcount_begin(&idle
->seqcount
);
97 idle_enter
= READ_ONCE(idle
->clock_idle_enter
);
98 idle_exit
= READ_ONCE(idle
->clock_idle_exit
);
99 } while (read_seqcount_retry(&idle
->seqcount
, seq
));
101 return cputime_to_nsecs(idle_enter
? ((idle_exit
?: now
) - idle_enter
) : 0);
104 void arch_cpu_idle_enter(void)
106 local_mcck_disable();
109 void arch_cpu_idle(void)
111 if (!test_cpu_flag(CIF_MCCK_PENDING
))
112 /* Halt the cpu and keep track of cpu time accounting. */
117 void arch_cpu_idle_exit(void)
120 if (test_cpu_flag(CIF_MCCK_PENDING
))
124 void arch_cpu_idle_dead(void)