.. | .. |
---|
16 | 16 | #include <linux/notifier.h> |
---|
17 | 17 | #include <linux/of_irq.h> |
---|
18 | 18 | #include <linux/percpu.h> |
---|
| 19 | +#include <linux/sched_clock.h> |
---|
19 | 20 | #include <linux/smp.h> |
---|
20 | 21 | #include <linux/time.h> |
---|
21 | 22 | #include <asm/mips-cps.h> |
---|
.. | .. |
---|
23 | 24 | static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device); |
---|
24 | 25 | static int gic_timer_irq; |
---|
25 | 26 | static unsigned int gic_frequency; |
---|
| 27 | +static bool __read_mostly gic_clock_unstable; |
---|
26 | 28 | |
---|
27 | | -static u64 notrace gic_read_count(void) |
---|
| 29 | +static void gic_clocksource_unstable(char *reason); |
---|
| 30 | + |
---|
| 31 | +static u64 notrace gic_read_count_2x32(void) |
---|
28 | 32 | { |
---|
29 | 33 | unsigned int hi, hi2, lo; |
---|
30 | | - |
---|
31 | | - if (mips_cm_is64) |
---|
32 | | - return read_gic_counter(); |
---|
33 | 34 | |
---|
34 | 35 | do { |
---|
35 | 36 | hi = read_gic_counter_32h(); |
---|
.. | .. |
---|
38 | 39 | } while (hi2 != hi); |
---|
39 | 40 | |
---|
40 | 41 | return (((u64) hi) << 32) + lo; |
---|
| 42 | +} |
---|
| 43 | + |
---|
| 44 | +static u64 notrace gic_read_count_64(void) |
---|
| 45 | +{ |
---|
| 46 | + return read_gic_counter(); |
---|
| 47 | +} |
---|
| 48 | + |
---|
| 49 | +static u64 notrace gic_read_count(void) |
---|
| 50 | +{ |
---|
| 51 | + if (mips_cm_is64) |
---|
| 52 | + return gic_read_count_64(); |
---|
| 53 | + |
---|
| 54 | + return gic_read_count_2x32(); |
---|
41 | 55 | } |
---|
42 | 56 | |
---|
43 | 57 | static int gic_next_event(unsigned long delta, struct clock_event_device *evt) |
---|
.. | .. |
---|
67 | 81 | return IRQ_HANDLED; |
---|
68 | 82 | } |
---|
69 | 83 | |
---|
70 | | -struct irqaction gic_compare_irqaction = { |
---|
| 84 | +static struct irqaction gic_compare_irqaction = { |
---|
71 | 85 | .handler = gic_compare_interrupt, |
---|
72 | 86 | .percpu_dev_id = &gic_clockevent_device, |
---|
73 | 87 | .flags = IRQF_PERCPU | IRQF_TIMER, |
---|
.. | .. |
---|
114 | 128 | { |
---|
115 | 129 | struct clk_notifier_data *cnd = data; |
---|
116 | 130 | |
---|
117 | | - if (action == POST_RATE_CHANGE) |
---|
| 131 | + if (action == POST_RATE_CHANGE) { |
---|
| 132 | + gic_clocksource_unstable("ref clock rate change"); |
---|
118 | 133 | on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); |
---|
| 134 | + } |
---|
119 | 135 | |
---|
120 | 136 | return NOTIFY_OK; |
---|
121 | 137 | } |
---|
.. | .. |
---|
155 | 171 | } |
---|
156 | 172 | |
---|
157 | 173 | static struct clocksource gic_clocksource = { |
---|
158 | | - .name = "GIC", |
---|
159 | | - .read = gic_hpt_read, |
---|
160 | | - .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
---|
161 | | - .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, |
---|
| 174 | + .name = "GIC", |
---|
| 175 | + .read = gic_hpt_read, |
---|
| 176 | + .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
---|
| 177 | + .vdso_clock_mode = VDSO_CLOCKMODE_GIC, |
---|
162 | 178 | }; |
---|
| 179 | + |
---|
| 180 | +static void gic_clocksource_unstable(char *reason) |
---|
| 181 | +{ |
---|
| 182 | + if (gic_clock_unstable) |
---|
| 183 | + return; |
---|
| 184 | + |
---|
| 185 | + gic_clock_unstable = true; |
---|
| 186 | + |
---|
| 187 | + pr_info("GIC timer is unstable due to %s\n", reason); |
---|
| 188 | + |
---|
| 189 | + clocksource_mark_unstable(&gic_clocksource); |
---|
| 190 | +} |
---|
163 | 191 | |
---|
164 | 192 | static int __init __gic_clocksource_init(void) |
---|
165 | 193 | { |
---|
.. | .. |
---|
228 | 256 | /* And finally start the counter */ |
---|
229 | 257 | clear_gic_config(GIC_CONFIG_COUNTSTOP); |
---|
230 | 258 | |
---|
| 259 | + /* |
---|
| 260 | + * It's safe to use the MIPS GIC timer as a sched clock source only if |
---|
| 261 | + * its ticks are stable, which is true on either the platforms with |
---|
| 262 | + * stable CPU frequency or on the platforms with CM3 and CPU frequency |
---|
| 263 | + * change performed by the CPC core clocks divider. |
---|
| 264 | + */ |
---|
| 265 | + if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) { |
---|
| 266 | + sched_clock_register(mips_cm_is64 ? |
---|
| 267 | + gic_read_count_64 : gic_read_count_2x32, |
---|
| 268 | + 64, gic_frequency); |
---|
| 269 | + } |
---|
| 270 | + |
---|
231 | 271 | return 0; |
---|
232 | 272 | } |
---|
233 | 273 | TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer", |
---|