0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clocksource.h>
0009 #include <linux/cpufreq.h>
0010 #include <linux/init.h>
0011 #include <linux/sched_clock.h>
0012
0013 #include <asm/time.h>
0014
0015 static u64 c0_hpt_read(struct clocksource *cs)
0016 {
0017 return read_c0_count();
0018 }
0019
0020 static struct clocksource clocksource_mips = {
0021 .name = "MIPS",
0022 .read = c0_hpt_read,
0023 .mask = CLOCKSOURCE_MASK(32),
0024 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
0025 };
0026
0027 static u64 __maybe_unused notrace r4k_read_sched_clock(void)
0028 {
0029 return read_c0_count();
0030 }
0031
0032 static inline unsigned int rdhwr_count(void)
0033 {
0034 unsigned int count;
0035
0036 __asm__ __volatile__(
0037 " .set push\n"
0038 " .set mips32r2\n"
0039 " rdhwr %0, $2\n"
0040 " .set pop\n"
0041 : "=r" (count));
0042
0043 return count;
0044 }
0045
0046 static bool rdhwr_count_usable(void)
0047 {
0048 unsigned int prev, curr, i;
0049
0050
0051
0052
0053
0054
0055
0056 for (i = 0, prev = rdhwr_count(); i < 100; i++) {
0057 curr = rdhwr_count();
0058
0059 if (curr != prev)
0060 return true;
0061
0062 prev = curr;
0063 }
0064
0065 pr_warn("Not using R4K clocksource in VDSO due to broken RDHWR\n");
0066 return false;
0067 }
0068
0069 #ifdef CONFIG_CPU_FREQ
0070
0071 static bool __read_mostly r4k_clock_unstable;
0072
0073 static void r4k_clocksource_unstable(char *reason)
0074 {
0075 if (r4k_clock_unstable)
0076 return;
0077
0078 r4k_clock_unstable = true;
0079
0080 pr_info("R4K timer is unstable due to %s\n", reason);
0081
0082 clocksource_mark_unstable(&clocksource_mips);
0083 }
0084
0085 static int r4k_cpufreq_callback(struct notifier_block *nb,
0086 unsigned long val, void *data)
0087 {
0088 if (val == CPUFREQ_POSTCHANGE)
0089 r4k_clocksource_unstable("CPU frequency change");
0090
0091 return 0;
0092 }
0093
0094 static struct notifier_block r4k_cpufreq_notifier = {
0095 .notifier_call = r4k_cpufreq_callback,
0096 };
0097
0098 static int __init r4k_register_cpufreq_notifier(void)
0099 {
0100 return cpufreq_register_notifier(&r4k_cpufreq_notifier,
0101 CPUFREQ_TRANSITION_NOTIFIER);
0102
0103 }
0104 core_initcall(r4k_register_cpufreq_notifier);
0105
0106 #endif
0107
0108 int __init init_r4k_clocksource(void)
0109 {
0110 if (!cpu_has_counter || !mips_hpt_frequency)
0111 return -ENXIO;
0112
0113
0114 clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
0115
0116
0117
0118
0119
0120 if (cpu_has_mips_r2_r6 && rdhwr_count_usable())
0121 clocksource_mips.vdso_clock_mode = VDSO_CLOCKMODE_R4K;
0122
0123 clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
0124
0125 #ifndef CONFIG_CPU_FREQ
0126 sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
0127 #endif
0128
0129 return 0;
0130 }