unsigned long processor_freq;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+unsigned long tb_to_ns_scale;
+unsigned long tb_to_ns_shift;
+
struct gettimeofday_struct do_gtod;
extern unsigned long wall_jiffies;
/*
* Scheduler clock - returns current time in nanosec units.
*
- * This is wrong, but my CPUs run at 1GHz, so nyer nyer.
+ * Note: mulhdu(a, b) (multiply high double unsigned) returns
+ * the high 64 bits of a * b, i.e. (a * b) >> 64, where a and b
+ * are 64-bit unsigned numbers.
*/
unsigned long long sched_clock(void)
{
- return get_tb();
+ return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift;
}
/*
/* This function is only called on the boot processor */
unsigned long flags;
struct rtc_time tm;
+ struct div_result res;
+ unsigned long scale, shift;
ppc_md.calibrate_decr();
+ /*
+ * Compute scale factor for sched_clock.
+ * The calibrate_decr() function has set tb_ticks_per_sec,
+ * which is the timebase frequency.
+ * We compute 1e9 * 2^64 / tb_ticks_per_sec and interpret
+ * the 128-bit result as a 64.64 fixed-point number.
+ * We then shift that number right until it is less than 1.0,
+ * giving us the scale factor and shift count to use in
+ * sched_clock().
+ */
+ div128_by_32(1000000000, 0, tb_ticks_per_sec, &res);
+ scale = res.result_low;
+ for (shift = 0; res.result_high != 0; ++shift) {
+ scale = (scale >> 1) | (res.result_high << 63);
+ res.result_high >>= 1;
+ }
+ tb_to_ns_scale = scale;
+ tb_to_ns_shift = shift;
+
#ifdef CONFIG_PPC_ISERIES
if (!piranha_simulator)
#endif