diff options
Diffstat (limited to 'arch/arm/kernel/sched_clock.c')
-rw-r--r-- | arch/arm/kernel/sched_clock.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c index 27d186abbc06..e21bac20d90d 100644 --- a/arch/arm/kernel/sched_clock.c +++ b/arch/arm/kernel/sched_clock.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/jiffies.h> | 10 | #include <linux/jiffies.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/moduleparam.h> | ||
12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
13 | #include <linux/syscore_ops.h> | 14 | #include <linux/syscore_ops.h> |
14 | #include <linux/timer.h> | 15 | #include <linux/timer.h> |
@@ -21,10 +22,15 @@ struct clock_data { | |||
21 | u32 epoch_cyc_copy; | 22 | u32 epoch_cyc_copy; |
22 | u32 mult; | 23 | u32 mult; |
23 | u32 shift; | 24 | u32 shift; |
25 | bool suspended; | ||
26 | bool needs_suspend; | ||
24 | }; | 27 | }; |
25 | 28 | ||
26 | static void sched_clock_poll(unsigned long wrap_ticks); | 29 | static void sched_clock_poll(unsigned long wrap_ticks); |
27 | static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0); | 30 | static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0); |
31 | static int irqtime = -1; | ||
32 | |||
33 | core_param(irqtime, irqtime, int, 0400); | ||
28 | 34 | ||
29 | static struct clock_data cd = { | 35 | static struct clock_data cd = { |
30 | .mult = NSEC_PER_SEC / HZ, | 36 | .mult = NSEC_PER_SEC / HZ, |
@@ -49,6 +55,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask) | |||
49 | u64 epoch_ns; | 55 | u64 epoch_ns; |
50 | u32 epoch_cyc; | 56 | u32 epoch_cyc; |
51 | 57 | ||
58 | if (cd.suspended) | ||
59 | return cd.epoch_ns; | ||
60 | |||
52 | /* | 61 | /* |
53 | * Load the epoch_cyc and epoch_ns atomically. We do this by | 62 | * Load the epoch_cyc and epoch_ns atomically. We do this by |
54 | * ensuring that we always write epoch_cyc, epoch_ns and | 63 | * ensuring that we always write epoch_cyc, epoch_ns and |
@@ -98,6 +107,13 @@ static void sched_clock_poll(unsigned long wrap_ticks) | |||
98 | update_sched_clock(); | 107 | update_sched_clock(); |
99 | } | 108 | } |
100 | 109 | ||
110 | void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits, | ||
111 | unsigned long rate) | ||
112 | { | ||
113 | setup_sched_clock(read, bits, rate); | ||
114 | cd.needs_suspend = true; | ||
115 | } | ||
116 | |||
101 | void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) | 117 | void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) |
102 | { | 118 | { |
103 | unsigned long r, w; | 119 | unsigned long r, w; |
@@ -145,6 +161,10 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) | |||
145 | */ | 161 | */ |
146 | cd.epoch_ns = 0; | 162 | cd.epoch_ns = 0; |
147 | 163 | ||
164 | /* Enable IRQ time accounting if we have a fast enough sched_clock */ | ||
165 | if (irqtime > 0 || (irqtime == -1 && rate >= 1000000)) | ||
166 | enable_sched_clock_irqtime(); | ||
167 | |||
148 | pr_debug("Registered %pF as sched_clock source\n", read); | 168 | pr_debug("Registered %pF as sched_clock source\n", read); |
149 | } | 169 | } |
150 | 170 | ||
@@ -169,11 +189,23 @@ void __init sched_clock_postinit(void) | |||
169 | static int sched_clock_suspend(void) | 189 | static int sched_clock_suspend(void) |
170 | { | 190 | { |
171 | sched_clock_poll(sched_clock_timer.data); | 191 | sched_clock_poll(sched_clock_timer.data); |
192 | if (cd.needs_suspend) | ||
193 | cd.suspended = true; | ||
172 | return 0; | 194 | return 0; |
173 | } | 195 | } |
174 | 196 | ||
197 | static void sched_clock_resume(void) | ||
198 | { | ||
199 | if (cd.needs_suspend) { | ||
200 | cd.epoch_cyc = read_sched_clock(); | ||
201 | cd.epoch_cyc_copy = cd.epoch_cyc; | ||
202 | cd.suspended = false; | ||
203 | } | ||
204 | } | ||
205 | |||
175 | static struct syscore_ops sched_clock_ops = { | 206 | static struct syscore_ops sched_clock_ops = { |
176 | .suspend = sched_clock_suspend, | 207 | .suspend = sched_clock_suspend, |
208 | .resume = sched_clock_resume, | ||
177 | }; | 209 | }; |
178 | 210 | ||
179 | static int __init sched_clock_syscore_init(void) | 211 | static int __init sched_clock_syscore_init(void) |