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 __kprobes
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
);
38 /* Account time spent with enabled wait psw loaded as idle time. */
41 idle_time
= idle
->clock_idle_exit
- idle
->clock_idle_enter
;
42 idle
->clock_idle_enter
= idle
->clock_idle_exit
= 0ULL;
43 idle
->idle_time
+= idle_time
;
45 account_idle_time(idle_time
);
50 static ssize_t
show_idle_count(struct device
*dev
,
51 struct device_attribute
*attr
, char *buf
)
53 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, dev
->id
);
54 unsigned long long idle_count
;
55 unsigned int sequence
;
58 sequence
= ACCESS_ONCE(idle
->sequence
);
59 idle_count
= ACCESS_ONCE(idle
->idle_count
);
60 if (ACCESS_ONCE(idle
->clock_idle_enter
))
62 } while ((sequence
& 1) || (ACCESS_ONCE(idle
->sequence
) != sequence
));
63 return sprintf(buf
, "%llu\n", idle_count
);
65 DEVICE_ATTR(idle_count
, 0444, show_idle_count
, NULL
);
67 static ssize_t
show_idle_time(struct device
*dev
,
68 struct device_attribute
*attr
, char *buf
)
70 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, dev
->id
);
71 unsigned long long now
, idle_time
, idle_enter
, idle_exit
;
72 unsigned int sequence
;
75 now
= get_tod_clock();
76 sequence
= ACCESS_ONCE(idle
->sequence
);
77 idle_time
= ACCESS_ONCE(idle
->idle_time
);
78 idle_enter
= ACCESS_ONCE(idle
->clock_idle_enter
);
79 idle_exit
= ACCESS_ONCE(idle
->clock_idle_exit
);
80 } while ((sequence
& 1) || (ACCESS_ONCE(idle
->sequence
) != sequence
));
81 idle_time
+= idle_enter
? ((idle_exit
? : now
) - idle_enter
) : 0;
82 return sprintf(buf
, "%llu\n", idle_time
>> 12);
84 DEVICE_ATTR(idle_time_us
, 0444, show_idle_time
, NULL
);
86 cputime64_t
arch_cpu_idle_time(int cpu
)
88 struct s390_idle_data
*idle
= &per_cpu(s390_idle
, cpu
);
89 unsigned long long now
, idle_enter
, idle_exit
;
90 unsigned int sequence
;
93 now
= get_tod_clock();
94 sequence
= ACCESS_ONCE(idle
->sequence
);
95 idle_enter
= ACCESS_ONCE(idle
->clock_idle_enter
);
96 idle_exit
= ACCESS_ONCE(idle
->clock_idle_exit
);
97 } while ((sequence
& 1) || (ACCESS_ONCE(idle
->sequence
) != sequence
));
98 return idle_enter
? ((idle_exit
?: now
) - idle_enter
) : 0;
101 void arch_cpu_idle_enter(void)
103 local_mcck_disable();
106 void arch_cpu_idle(void)
108 if (!test_cpu_flag(CIF_MCCK_PENDING
))
109 /* Halt the cpu and keep track of cpu time accounting. */
114 void arch_cpu_idle_exit(void)
117 if (test_cpu_flag(CIF_MCCK_PENDING
))
121 void arch_cpu_idle_dead(void)