#include <asm/prom.h>
#include <asm/irq.h>
#include <asm/div64.h>
+#include <asm/smp.h>
#ifdef CONFIG_PPC64
#include <asm/systemcfg.h>
#include <asm/firmware.h>
#endif
#ifdef CONFIG_PPC_ISERIES
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/iSeries/HvCallXm.h>
+#include <asm/iseries/it_lp_queue.h>
+#include <asm/iseries/hv_call_xm.h>
#endif
-u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
-
-EXPORT_SYMBOL(jiffies_64);
-
/* keep track of when we need to update the rtc */
time_t last_rtc_update;
extern int piranha_simulator;
unsigned long ppc_proc_freq;
unsigned long ppc_tb_freq;
-#ifdef CONFIG_PPC32 /* XXX for now */
-#define boot_cpuid 0
-#endif
+u64 tb_last_jiffy __cacheline_aligned_in_smp;
+unsigned long tb_last_stamp;
+
+/*
+ * Note that on ppc32 this only stores the bottom 32 bits of
+ * the timebase value, but that's enough to tell when a jiffy
+ * has passed.
+ */
+DEFINE_PER_CPU(unsigned long, last_jiffy);
static __inline__ void timer_check_rtc(void)
{
* We should have an rtc call that only sets the minutes and
* seconds like on Intel to avoid problems with non UTC clocks.
*/
- if (ntp_synced() &&
+ if (ppc_md.set_rtc_time && ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ &&
jiffies - wall_jiffies == 1) {
void do_gettimeofday(struct timeval *tv)
{
+ if (__USE_RTC()) {
+ /* do this the old way */
+ unsigned long flags, seq;
+ unsigned int sec, nsec, usec, lost;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ sec = xtime.tv_sec;
+ nsec = xtime.tv_nsec + tb_ticks_since(tb_last_stamp);
+ lost = jiffies - wall_jiffies;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+ usec = nsec / 1000 + lost * (1000000 / HZ);
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ ++sec;
+ }
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+ return;
+ }
__do_gettimeofday(tv, get_tb());
}
* between updates.
*/
static inline void update_gtod(u64 new_tb_stamp, u64 new_stamp_xsec,
- unsigned int new_tb_to_xs)
+ u64 new_tb_to_xs)
{
unsigned temp_idx;
struct gettimeofday_vars *temp_varp;
unsigned long offset;
u64 new_stamp_xsec;
+ if (__USE_RTC())
+ return;
offset = cur_tb - do_gtod.varp->tb_orig_stamp;
if ((offset & 0x80000000u) == 0)
return;
* call will not be needed)
*/
-u64 tb_last_stamp __cacheline_aligned_in_smp;
-
-/*
- * Note that on ppc32 this only stores the bottom 32 bits of
- * the timebase value, but that's enough to tell when a jiffy
- * has passed.
- */
-DEFINE_PER_CPU(unsigned long, last_jiffy);
-
/*
* timer_interrupt - gets called when the decrementer overflows,
* with interrupts disabled.
continue;
write_seqlock(&xtime_lock);
- tb_last_stamp += tb_ticks_per_jiffy;
- timer_recalc_offset(tb_last_stamp);
+ tb_last_jiffy += tb_ticks_per_jiffy;
+ tb_last_stamp = per_cpu(last_jiffy, cpu);
+ timer_recalc_offset(tb_last_jiffy);
do_timer(regs);
- timer_sync_xtime(tb_last_stamp);
+ timer_sync_xtime(tb_last_jiffy);
timer_check_rtc();
write_sequnlock(&xtime_lock);
if (adjusting_time && (time_adjust == 0))
* We don't expect this to be called on a machine with a 601,
* so using get_tbl is fine.
*/
- tb_last_stamp = get_tb();
+ tb_last_stamp = tb_last_jiffy = get_tb();
for_each_cpu(i)
per_cpu(last_jiffy, i) = tb_last_stamp;
}
-#ifdef CONFIG_SMPxxx
+#ifdef CONFIG_SMP
void __init smp_space_timers(unsigned int max_cpus)
{
int i;
*/
unsigned long long sched_clock(void)
{
+ if (__USE_RTC())
+ return get_rtc();
return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift;
}
long wtm_nsec, new_nsec = tv->tv_nsec;
unsigned long flags;
long int tb_delta;
- u64 new_xsec;
+ u64 new_xsec, tb_delta_xs;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
#endif
tb_delta = tb_ticks_since(tb_last_stamp);
tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
-
- new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta);
+ tb_delta_xs = mulhdu(tb_delta, do_gtod.varp->tb_to_xs);
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec);
ntp_clear();
- new_xsec = (u64)new_nsec * XSEC_PER_SEC;
- do_div(new_xsec, NSEC_PER_SEC);
- new_xsec += (u64)new_sec * XSEC_PER_SEC;
- update_gtod(tb_last_stamp, new_xsec, do_gtod.varp->tb_to_xs);
+ new_xsec = 0;
+ if (new_nsec != 0) {
+ new_xsec = (u64)new_nsec * XSEC_PER_SEC;
+ do_div(new_xsec, NSEC_PER_SEC);
+ }
+ new_xsec += (u64)new_sec * XSEC_PER_SEC - tb_delta_xs;
+ update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
#ifdef CONFIG_PPC64
systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
EXPORT_SYMBOL(do_settimeofday);
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA) || defined(CONFIG_PPC_ISERIES)
void __init generic_calibrate_decr(void)
{
struct device_node *cpu;
- struct div_result divres;
unsigned int *fp;
int node_found;
ppc_proc_freq = *fp;
}
}
+#ifdef CONFIG_BOOKE
+ /* Set the time base to zero */
+ mtspr(SPRN_TBWL, 0);
+ mtspr(SPRN_TBWU, 0);
+
+ /* Clear any pending timer interrupts */
+ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+ /* Enable decrementer interrupt */
+ mtspr(SPRN_TCR, TCR_DIE);
+#endif
if (!node_found)
printk(KERN_ERR "WARNING: Estimating processor frequency "
"(not found)\n");
of_node_put(cpu);
-
- printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
- ppc_tb_freq/1000000, ppc_tb_freq%1000000);
- printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n",
- ppc_proc_freq/1000000, ppc_proc_freq%1000000);
-
- tb_ticks_per_jiffy = ppc_tb_freq / HZ;
- tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
- tb_ticks_per_usec = ppc_tb_freq / 1000000;
- tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
- div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres);
- tb_to_xs = divres.result_low;
}
-#endif
unsigned long get_boot_time(void)
{
if (ppc_md.time_init != NULL)
timezone_offset = ppc_md.time_init();
- ppc_md.calibrate_decr();
+ if (__USE_RTC()) {
+ /* 601 processor: dec counts down by 128 every 128ns */
+ ppc_tb_freq = 1000000000;
+ tb_last_stamp = get_rtcl();
+ tb_last_jiffy = tb_last_stamp;
+ } else {
+ /* Normal PowerPC with timebase register */
+ ppc_md.calibrate_decr();
+ printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
+ printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n",
+ ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
+ tb_last_stamp = tb_last_jiffy = get_tb();
+ }
+
+ tb_ticks_per_jiffy = ppc_tb_freq / HZ;
+ tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
+ tb_ticks_per_usec = ppc_tb_freq / 1000000;
+ tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
+ div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res);
+ tb_to_xs = res.result_low;
#ifdef CONFIG_PPC64
get_paca()->default_decr = tb_ticks_per_jiffy;
write_seqlock_irqsave(&xtime_lock, flags);
xtime.tv_sec = tm;
xtime.tv_nsec = 0;
- tb_last_stamp = get_tb();
do_gtod.varp = &do_gtod.vars[0];
do_gtod.var_idx = 0;
- do_gtod.varp->tb_orig_stamp = tb_last_stamp;
+ do_gtod.varp->tb_orig_stamp = tb_last_jiffy;
__get_cpu_var(last_jiffy) = tb_last_stamp;
do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
do_gtod.varp->tb_to_xs = tb_to_xs;
do_gtod.tb_to_us = tb_to_us;
#ifdef CONFIG_PPC64
- systemcfg->tb_orig_stamp = tb_last_stamp;
+ systemcfg->tb_orig_stamp = tb_last_jiffy;
systemcfg->tb_update_count = 0;
systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
w = a / divisor;
ra = ((u64)(a - (w * divisor)) << 32) + b;
-#ifdef CONFIG_PPC64
- x = ra / divisor;
- rb = ((ra - (x * divisor)) << 32) + c;
-
- y = rb / divisor;
- rc = ((rb - (y * divisor)) << 32) + d;
-
- z = rc / divisor;
-#else
- /* for 32-bit, use do_div from div64.h */
rb = ((u64) do_div(ra, divisor) << 32) + c;
x = ra;
do_div(rc, divisor);
z = rc;
-#endif
dr->result_high = ((u64)w << 32) + x;
dr->result_low = ((u64)y << 32) + z;
}
-