| .. | .. |
|---|
| 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", |
|---|