.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | | - * sched_clock.c: Generic sched_clock() support, to extend low level |
---|
3 | | - * hardware time counters to full 64-bit ns values. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License version 2 as |
---|
7 | | - * published by the Free Software Foundation. |
---|
| 3 | + * Generic sched_clock() support, to extend low level hardware time |
---|
| 4 | + * counters to full 64-bit ns values. |
---|
8 | 5 | */ |
---|
9 | 6 | #include <linux/clocksource.h> |
---|
10 | 7 | #include <linux/init.h> |
---|
.. | .. |
---|
19 | 16 | #include <linux/sched_clock.h> |
---|
20 | 17 | #include <linux/seqlock.h> |
---|
21 | 18 | #include <linux/bitops.h> |
---|
| 19 | +#include <trace/hooks/epoch.h> |
---|
22 | 20 | |
---|
23 | | -/** |
---|
24 | | - * struct clock_read_data - data required to read from sched_clock() |
---|
25 | | - * |
---|
26 | | - * @epoch_ns: sched_clock() value at last update |
---|
27 | | - * @epoch_cyc: Clock cycle value at last update. |
---|
28 | | - * @sched_clock_mask: Bitmask for two's complement subtraction of non 64bit |
---|
29 | | - * clocks. |
---|
30 | | - * @read_sched_clock: Current clock source (or dummy source when suspended). |
---|
31 | | - * @mult: Multipler for scaled math conversion. |
---|
32 | | - * @shift: Shift value for scaled math conversion. |
---|
33 | | - * |
---|
34 | | - * Care must be taken when updating this structure; it is read by |
---|
35 | | - * some very hot code paths. It occupies <=40 bytes and, when combined |
---|
36 | | - * with the seqcount used to synchronize access, comfortably fits into |
---|
37 | | - * a 64 byte cache line. |
---|
38 | | - */ |
---|
39 | | -struct clock_read_data { |
---|
40 | | - u64 epoch_ns; |
---|
41 | | - u64 epoch_cyc; |
---|
42 | | - u64 sched_clock_mask; |
---|
43 | | - u64 (*read_sched_clock)(void); |
---|
44 | | - u32 mult; |
---|
45 | | - u32 shift; |
---|
46 | | -}; |
---|
| 21 | +#include "timekeeping.h" |
---|
47 | 22 | |
---|
48 | 23 | /** |
---|
49 | 24 | * struct clock_data - all data needed for sched_clock() (including |
---|
.. | .. |
---|
61 | 36 | * into a single 64-byte cache line. |
---|
62 | 37 | */ |
---|
63 | 38 | struct clock_data { |
---|
64 | | - seqcount_t seq; |
---|
| 39 | + seqcount_latch_t seq; |
---|
65 | 40 | struct clock_read_data read_data[2]; |
---|
66 | 41 | ktime_t wrap_kt; |
---|
67 | 42 | unsigned long rate; |
---|
.. | .. |
---|
94 | 69 | return (cyc * mult) >> shift; |
---|
95 | 70 | } |
---|
96 | 71 | |
---|
| 72 | +notrace struct clock_read_data *sched_clock_read_begin(unsigned int *seq) |
---|
| 73 | +{ |
---|
| 74 | + *seq = raw_read_seqcount_latch(&cd.seq); |
---|
| 75 | + return cd.read_data + (*seq & 1); |
---|
| 76 | +} |
---|
| 77 | + |
---|
| 78 | +notrace int sched_clock_read_retry(unsigned int seq) |
---|
| 79 | +{ |
---|
| 80 | + return read_seqcount_latch_retry(&cd.seq, seq); |
---|
| 81 | +} |
---|
| 82 | + |
---|
97 | 83 | unsigned long long notrace sched_clock(void) |
---|
98 | 84 | { |
---|
99 | 85 | u64 cyc, res; |
---|
100 | | - unsigned long seq; |
---|
| 86 | + unsigned int seq; |
---|
101 | 87 | struct clock_read_data *rd; |
---|
102 | 88 | |
---|
103 | 89 | do { |
---|
104 | | - seq = raw_read_seqcount(&cd.seq); |
---|
105 | | - rd = cd.read_data + (seq & 1); |
---|
| 90 | + rd = sched_clock_read_begin(&seq); |
---|
106 | 91 | |
---|
107 | 92 | cyc = (rd->read_sched_clock() - rd->epoch_cyc) & |
---|
108 | 93 | rd->sched_clock_mask; |
---|
109 | 94 | res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift); |
---|
110 | | - } while (read_seqcount_retry(&cd.seq, seq)); |
---|
| 95 | + } while (sched_clock_read_retry(seq)); |
---|
111 | 96 | |
---|
112 | 97 | return res; |
---|
113 | 98 | } |
---|
.. | .. |
---|
165 | 150 | return HRTIMER_RESTART; |
---|
166 | 151 | } |
---|
167 | 152 | |
---|
168 | | -void __init |
---|
169 | | -sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) |
---|
| 153 | +void sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) |
---|
170 | 154 | { |
---|
171 | 155 | u64 res, wrap, new_mask, new_epoch, cyc, ns; |
---|
172 | 156 | u32 new_mult, new_shift; |
---|
173 | | - unsigned long r; |
---|
| 157 | + unsigned long r, flags; |
---|
174 | 158 | char r_unit; |
---|
175 | 159 | struct clock_read_data rd; |
---|
176 | 160 | |
---|
177 | 161 | if (cd.rate > rate) |
---|
178 | 162 | return; |
---|
179 | 163 | |
---|
180 | | - WARN_ON(!irqs_disabled()); |
---|
| 164 | + /* Cannot register a sched_clock with interrupts on */ |
---|
| 165 | + local_irq_save(flags); |
---|
181 | 166 | |
---|
182 | 167 | /* Calculate the mult/shift to convert counter ticks to ns. */ |
---|
183 | 168 | clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600); |
---|
.. | .. |
---|
208 | 193 | |
---|
209 | 194 | if (sched_clock_timer.function != NULL) { |
---|
210 | 195 | /* update timeout for clock wrap */ |
---|
211 | | - hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); |
---|
| 196 | + hrtimer_start(&sched_clock_timer, cd.wrap_kt, |
---|
| 197 | + HRTIMER_MODE_REL_HARD); |
---|
212 | 198 | } |
---|
213 | 199 | |
---|
214 | 200 | r = rate; |
---|
.. | .. |
---|
234 | 220 | if (irqtime > 0 || (irqtime == -1 && rate >= 1000000)) |
---|
235 | 221 | enable_sched_clock_irqtime(); |
---|
236 | 222 | |
---|
237 | | - pr_debug("Registered %pF as sched_clock source\n", read); |
---|
| 223 | + local_irq_restore(flags); |
---|
| 224 | + |
---|
| 225 | + pr_debug("Registered %pS as sched_clock source\n", read); |
---|
238 | 226 | } |
---|
| 227 | +EXPORT_SYMBOL_GPL(sched_clock_register); |
---|
239 | 228 | |
---|
240 | 229 | void __init generic_sched_clock_init(void) |
---|
241 | 230 | { |
---|
242 | 231 | /* |
---|
243 | 232 | * If no sched_clock() function has been provided at that point, |
---|
244 | | - * make it the final one one. |
---|
| 233 | + * make it the final one. |
---|
245 | 234 | */ |
---|
246 | 235 | if (cd.actual_read_sched_clock == jiffy_sched_clock_read) |
---|
247 | 236 | sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ); |
---|
.. | .. |
---|
252 | 241 | * Start the timer to keep sched_clock() properly updated and |
---|
253 | 242 | * sets the initial epoch. |
---|
254 | 243 | */ |
---|
255 | | - hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
---|
| 244 | + hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); |
---|
256 | 245 | sched_clock_timer.function = sched_clock_poll; |
---|
257 | | - hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); |
---|
| 246 | + hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD); |
---|
258 | 247 | } |
---|
259 | 248 | |
---|
260 | 249 | /* |
---|
.. | .. |
---|
270 | 259 | */ |
---|
271 | 260 | static u64 notrace suspended_sched_clock_read(void) |
---|
272 | 261 | { |
---|
273 | | - unsigned long seq = raw_read_seqcount(&cd.seq); |
---|
| 262 | + unsigned int seq = raw_read_seqcount_latch(&cd.seq); |
---|
274 | 263 | |
---|
275 | 264 | return cd.read_data[seq & 1].epoch_cyc; |
---|
276 | 265 | } |
---|
.. | .. |
---|
282 | 271 | update_sched_clock(); |
---|
283 | 272 | hrtimer_cancel(&sched_clock_timer); |
---|
284 | 273 | rd->read_sched_clock = suspended_sched_clock_read; |
---|
| 274 | + trace_android_vh_show_suspend_epoch_val(rd->epoch_ns, rd->epoch_cyc); |
---|
285 | 275 | |
---|
286 | 276 | return 0; |
---|
287 | 277 | } |
---|
.. | .. |
---|
291 | 281 | struct clock_read_data *rd = &cd.read_data[0]; |
---|
292 | 282 | |
---|
293 | 283 | rd->epoch_cyc = cd.actual_read_sched_clock(); |
---|
294 | | - hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); |
---|
| 284 | + hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD); |
---|
295 | 285 | rd->read_sched_clock = cd.actual_read_sched_clock; |
---|
| 286 | + trace_android_vh_show_resume_epoch_val(rd->epoch_cyc); |
---|
296 | 287 | } |
---|
297 | 288 | |
---|
298 | 289 | static struct syscore_ops sched_clock_ops = { |
---|