2 * Idle functions for s390.
4 * Copyright IBM Corp. 2014
6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
9 #include <linux/kernel.h>
10 #include <linux/kernel_stat.h>
11 #include <linux/kprobes.h>
12 #include <linux/notifier.h>
13 #include <linux/init.h>
14 #include <linux/cpu.h>
15 #include <asm/cputime.h>
20 static DEFINE_PER_CPU(struct s390_idle_data
, s390_idle
);
22 void enabled_wait(void)
24 struct s390_idle_data
*idle
= this_cpu_ptr(&s390_idle
);
25 unsigned long long idle_time
;
26 unsigned long psw_mask
;
30 /* Wait for external, I/O or machine check interrupt. */
31 psw_mask
= PSW_KERNEL_BITS
| PSW_MASK_WAIT
| PSW_MASK_DAT
|
32 PSW_MASK_IO
| PSW_MASK_EXT
| PSW_MASK_MCHECK
;
33 clear_cpu_flag(CIF_NOHZ_DELAY
);
35 /* Call the assembler magic in entry.S */
36 psw_idle(idle
, psw_mask
);
40 /* Account time spent with enabled wait psw loaded as idle time. */
41 write_seqcount_begin(&idle
->seqcount
);
42 idle_time
= idle
->clock_idle_exit
- idle
->clock_idle_enter
;
43 idle
->clock_idle_enter
= idle
->clock_idle_exit
= 0ULL;
44 idle
->idle_time
+= idle_time
;
46 account_idle_time(idle_time
);
47 write_seqcount_end(&idle
->seqcount
);
49 NOKPROBE_SYMBOL(enabled_wait
);
51 static ssize_t
show_idle_count(struct device
*dev
,
52 struct device_attribute
*attr
, char *buf
)
54 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, dev
->id
);
55 unsigned long long idle_count
;
59 seq
= read_seqcount_begin(&idle
->seqcount
);
60 idle_count
= ACCESS_ONCE(idle
->idle_count
);
61 if (ACCESS_ONCE(idle
->clock_idle_enter
))
63 } while (read_seqcount_retry(&idle
->seqcount
, seq
));
64 return sprintf(buf
, "%llu\n", idle_count
);
66 DEVICE_ATTR(idle_count
, 0444, show_idle_count
, NULL
);
68 static ssize_t
show_idle_time(struct device
*dev
,
69 struct device_attribute
*attr
, char *buf
)
71 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, dev
->id
);
72 unsigned long long now
, idle_time
, idle_enter
, idle_exit
;
76 now
= get_tod_clock();
77 seq
= read_seqcount_begin(&idle
->seqcount
);
78 idle_time
= ACCESS_ONCE(idle
->idle_time
);
79 idle_enter
= ACCESS_ONCE(idle
->clock_idle_enter
);
80 idle_exit
= ACCESS_ONCE(idle
->clock_idle_exit
);
81 } while (read_seqcount_retry(&idle
->seqcount
, seq
));
82 idle_time
+= idle_enter
? ((idle_exit
? : now
) - idle_enter
) : 0;
83 return sprintf(buf
, "%llu\n", idle_time
>> 12);
85 DEVICE_ATTR(idle_time_us
, 0444, show_idle_time
, NULL
);
87 cputime64_t
arch_cpu_idle_time(int cpu
)
89 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, cpu
);
90 unsigned long long now
, idle_enter
, idle_exit
;
94 now
= get_tod_clock();
95 seq
= read_seqcount_begin(&idle
->seqcount
);
96 idle_enter
= ACCESS_ONCE(idle
->clock_idle_enter
);
97 idle_exit
= ACCESS_ONCE(idle
->clock_idle_exit
);
98 } while (read_seqcount_retry(&idle
->seqcount
, seq
));
99 return idle_enter
? ((idle_exit
?: now
) - idle_enter
) : 0;
102 void arch_cpu_idle_enter(void)
104 local_mcck_disable();
107 void arch_cpu_idle(void)
109 if (!test_cpu_flag(CIF_MCCK_PENDING
))
110 /* Halt the cpu and keep track of cpu time accounting. */
115 void arch_cpu_idle_exit(void)
118 if (test_cpu_flag(CIF_MCCK_PENDING
))
122 void arch_cpu_idle_dead(void)