aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/clockchips.h7
-rw-r--r--include/linux/clocksource.h10
-rw-r--r--kernel/time/clocksource.c53
3 files changed, 70 insertions, 0 deletions
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 3b5841016276..4d438b0bc10a 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -130,6 +130,13 @@ extern int clockevents_program_event(struct clock_event_device *dev,
130 130
131extern void clockevents_handle_noop(struct clock_event_device *dev); 131extern void clockevents_handle_noop(struct clock_event_device *dev);
132 132
133static inline void
134clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec)
135{
136 return clocks_calc_mult_shift(&ce->mult, &ce->shift, NSEC_PER_SEC,
137 freq, minsec);
138}
139
133#ifdef CONFIG_GENERIC_CLOCKEVENTS 140#ifdef CONFIG_GENERIC_CLOCKEVENTS
134extern void clockevents_notify(unsigned long reason, void *arg); 141extern void clockevents_notify(unsigned long reason, void *arg);
135#else 142#else
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 83d2fbd81b93..f57f88250526 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -279,6 +279,16 @@ extern void clocksource_resume(void);
279extern struct clocksource * __init __weak clocksource_default_clock(void); 279extern struct clocksource * __init __weak clocksource_default_clock(void);
280extern void clocksource_mark_unstable(struct clocksource *cs); 280extern void clocksource_mark_unstable(struct clocksource *cs);
281 281
282extern void
283clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec);
284
285static inline void
286clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec)
287{
288 return clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
289 NSEC_PER_SEC, minsec);
290}
291
282#ifdef CONFIG_GENERIC_TIME_VSYSCALL 292#ifdef CONFIG_GENERIC_TIME_VSYSCALL
283extern void update_vsyscall(struct timespec *ts, struct clocksource *c); 293extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
284extern void update_vsyscall_tz(void); 294extern void update_vsyscall_tz(void);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 5e18c6ab2c6a..407c0894ef37 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -107,6 +107,59 @@ u64 timecounter_cyc2time(struct timecounter *tc,
107} 107}
108EXPORT_SYMBOL(timecounter_cyc2time); 108EXPORT_SYMBOL(timecounter_cyc2time);
109 109
110/**
111 * clocks_calc_mult_shift - calculate mult/shift factors for scaled math of clocks
112 * @mult: pointer to mult variable
113 * @shift: pointer to shift variable
114 * @from: frequency to convert from
115 * @to: frequency to convert to
116 * @minsec: guaranteed runtime conversion range in seconds
117 *
118 * The function evaluates the shift/mult pair for the scaled math
119 * operations of clocksources and clockevents.
120 *
121 * @to and @from are frequency values in HZ. For clock sources @to is
122 * NSEC_PER_SEC == 1GHz and @from is the counter frequency. For clock
123 * event @to is the counter frequency and @from is NSEC_PER_SEC.
124 *
125 * The @minsec conversion range argument controls the time frame in
126 * seconds which must be covered by the runtime conversion with the
127 * calculated mult and shift factors. This guarantees that no 64bit
128 * overflow happens when the input value of the conversion is
129 * multiplied with the calculated mult factor. Larger ranges may
130 * reduce the conversion accuracy by chosing smaller mult and shift
131 * factors.
132 */
133void
134clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec)
135{
136 u64 tmp;
137 u32 sft, sftacc= 32;
138
139 /*
140 * Calculate the shift factor which is limiting the conversion
141 * range:
142 */
143 tmp = ((u64)minsec * from) >> 32;
144 while (tmp) {
145 tmp >>=1;
146 sftacc--;
147 }
148
149 /*
150 * Find the conversion shift/mult pair which has the best
151 * accuracy and fits the maxsec conversion range:
152 */
153 for (sft = 32; sft > 0; sft--) {
154 tmp = (u64) to << sft;
155 do_div(tmp, from);
156 if ((tmp >> sftacc) == 0)
157 break;
158 }
159 *mult = tmp;
160 *shift = sft;
161}
162
110/*[Clocksource internal variables]--------- 163/*[Clocksource internal variables]---------
111 * curr_clocksource: 164 * curr_clocksource:
112 * currently selected clocksource. 165 * currently selected clocksource.