/* This function is only called on the boot processor */ void __init time_init(void) { time_t sec, old_sec; unsigned old_stamp, stamp, elapsed; if (ppc_md.time_init != NULL) time_offset = ppc_md.time_init(); if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ tb_ticks_per_jiffy = DECREMENTER_COUNT_601; /* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */ tb_to_us = 0x418937; } else { ppc_md.calibrate_decr(); } /* Now that the decrementer is calibrated, it can be used in case the * clock is stuck, but the fact that we have to handle the 601 * makes things more complex. Repeatedly read the RTC until the * next second boundary to try to achieve some precision. If there * is no RTC, we still need to set tb_last_stamp and * last_jiffy_stamp(cpu 0) to the current stamp. */ stamp = get_native_tbl(); if (ppc_md.get_rtc_time) { sec = ppc_md.get_rtc_time(); elapsed = 0; do { old_stamp = stamp; old_sec = sec; stamp = get_native_tbl(); if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000; elapsed += stamp - old_stamp; sec = ppc_md.get_rtc_time(); } while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy); if (sec == old_sec) printk("Warning: real time clock seems stuck!\n"); xtime.tv_sec = sec; xtime.tv_usec = 0; /* No update now, we just read the time from the RTC ! */ last_rtc_update = xtime.tv_sec; } last_jiffy_stamp(0) = tb_last_stamp = stamp; /* Not exact, but the timer interrupt takes care of this */ set_dec(tb_ticks_per_jiffy); /* If platform provided a timezone (pmac), we correct the time * using do_sys_settimeofday() which in turn calls warp_clock() */ if (time_offset) { struct timezone tz; tz.tz_minuteswest = -time_offset / 60; tz.tz_dsttime = 0; do_sys_settimeofday(NULL, &tz); } }
void wakeup_decrementer(void) { set_dec(tb_ticks_per_jiffy); /* No currently-supported powerbook has a 601, * so use get_tbl, not native */ last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); }
int do_settimeofday(struct timespec *tv) { time_t wtm_sec, new_sec = tv->tv_sec; long wtm_nsec, new_nsec = tv->tv_nsec; unsigned long flags; int tb_delta; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; write_seqlock_irqsave(&xtime_lock, flags); /* Updating the RTC is not the job of this code. If the time is * stepped under NTP, the RTC will be update after STA_UNSYNC * is cleared. Tool like clock/hwclock either copy the RTC * to the system time, in which case there is no point in writing * to the RTC again, or write to the RTC but then they don't call * settimeofday to perform this operation. Note also that * we don't touch the decrementer since: * a) it would lose timer interrupt synchronization on SMP * (if it is working one day) * b) it could make one jiffy spuriously shorter or longer * which would introduce another source of uncertainty potentially * harmful to relatively short timers. */ /* This works perfectly on SMP only if the tb are in sync but * guarantees an error < 1 jiffy even if they are off by eons, * still reasonable when gettimeofday resolution is 1 jiffy. */ tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id())); tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta); wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); set_normalized_timespec(&xtime, new_sec, new_nsec); set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); /* In case of a large backwards jump in time with NTP, we want the * clock to be updated as soon as the PLL is again in lock. */ last_rtc_update = new_sec - 658; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; write_sequnlock_irqrestore(&xtime_lock, flags); clock_was_set(); return 0; }
static void __init smp_chrp_setup_cpu(int cpu_nr) { static atomic_t ready = ATOMIC_INIT(1); static volatile int frozen = 0; if (cpu_nr == 0) { /* wait for all the others */ while (atomic_read(&ready) < smp_num_cpus) barrier(); atomic_set(&ready, 1); /* freeze the timebase */ call_rtas("freeze-time-base", 0, 1, NULL); mb(); frozen = 1; /* XXX assumes this is not a 601 */ set_tb(0, 0); last_jiffy_stamp(0) = 0; while (atomic_read(&ready) < smp_num_cpus) barrier(); /* thaw the timebase again */ call_rtas("thaw-time-base", 0, 1, NULL); mb(); frozen = 0; smp_tb_synchronized = 1; } else { atomic_inc(&ready); while (!frozen) barrier(); set_tb(0, 0); last_jiffy_stamp(0) = 0; mb(); atomic_inc(&ready); while (frozen) barrier(); } if (OpenPIC_Addr) do_openpic_setup_cpu(); }
void __init smp_software_tb_sync(int cpu) { #define PASSES 4 /* 4 passes.. */ int pass; int i, j; /* stop - start will be the number of timebase ticks it takes for cpu0 * to send a message to all others and the first reponse to show up. * * ASSUMPTION: this time is similiar for all cpus * ASSUMPTION: the time to send a one-way message is ping/2 */ register unsigned long start = 0; register unsigned long stop = 0; register unsigned long temp = 0; set_tb(0, 0); /* multiple passes to get in l1 cache.. */ for (pass = 2; pass < 2+PASSES; pass++){ if (cpu == 0){ mb(); for (i = j = 1; i < smp_num_cpus; i++, j++){ /* skip stuck cpus */ while (!cpu_callin_map[j]) ++j; while (cpu_callin_map[j] != pass) barrier(); } mb(); tb_sync_flag = pass; start = get_tbl(); /* start timing */ while (tb_sync_flag) mb(); stop = get_tbl(); /* end timing */ /* theoretically, the divisor should be 2, but * I get better results on my dual mtx. someone * please report results on other smp machines.. */ tb_offset = (stop-start)/4; mb(); tb_sync_flag = pass; udelay(10); mb(); tb_sync_flag = 0; mb(); set_tb(0,0); mb(); } else { cpu_callin_map[cpu] = pass; mb(); while (!tb_sync_flag) mb(); /* wait for cpu0 */ mb(); tb_sync_flag = 0; /* send response for timing */ mb(); while (!tb_sync_flag) mb(); temp = tb_offset; /* make sure offset is loaded */ while (tb_sync_flag) mb(); set_tb(0,temp); /* now, set the timebase */ mb(); } } if (cpu == 0) { smp_tb_synchronized = 1; printk("smp_software_tb_sync: %d passes, final offset: %ld\n", PASSES, tb_offset); } /* so time.c doesn't get confused */ set_dec(tb_ticks_per_jiffy); last_jiffy_stamp(cpu) = 0; }
/* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. * We set it up to overflow again in 1/HZ seconds. */ void timer_interrupt(struct pt_regs * regs) { int next_dec; unsigned long cpu = smp_processor_id(); unsigned jiffy_stamp = last_jiffy_stamp(cpu); extern void do_IRQ(struct pt_regs *); if (atomic_read(&ppc_n_lost_interrupts) != 0) do_IRQ(regs); MARK(kernel_trap_entry, "%d struct pt_regs %p", regs->trap, regs); irq_enter(); while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { jiffy_stamp += tb_ticks_per_jiffy; profile_tick(CPU_PROFILING, regs); update_process_times(user_mode(regs)); if (smp_processor_id()) continue; /* We are in an interrupt, no need to save/restore flags */ write_seqlock(&xtime_lock); tb_last_stamp = jiffy_stamp; #ifdef CONFIG_LTT ltt_reset_timestamp(); #endif //CONFIG_LTT do_timer(regs); /* * update the rtc when needed, this should be performed on the * right fraction of a second. Half or full second ? * Full second works on mk48t59 clocks, others need testing. * Note that this update is basically only used through * the adjtimex system calls. Setting the HW clock in * any other way is a /dev/rtc and userland business. * This is still wrong by -0.5/+1.5 jiffies because of the * timer interrupt resolution and possible delay, but here we * hit a quantization limit which can only be solved by higher * resolution timers and decoupling time management from timer * interrupts. This is also wrong on the clocks * which require being written at the half second boundary. * We should have an rtc call that only sets the minutes and * seconds like on Intel to avoid problems with non UTC clocks. */ 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) { if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0) last_rtc_update = xtime.tv_sec+1; else /* Try again one minute later */ last_rtc_update += 60; } write_sequnlock(&xtime_lock); } if ( !disarm_decr[smp_processor_id()] ) set_dec(next_dec); last_jiffy_stamp(cpu) = jiffy_stamp; if (ppc_md.heartbeat && !ppc_md.heartbeat_count--) ppc_md.heartbeat(); irq_exit(); trace_kernel_trap_exit(); MARK(kernel_trap_exit, MARK_NOARGS); }
/* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. * We set it up to overflow again in 1/HZ seconds. */ int timer_interrupt(struct pt_regs * regs) { int next_dec; unsigned long cpu = smp_processor_id(); unsigned jiffy_stamp = last_jiffy_stamp(cpu); extern void do_IRQ(struct pt_regs *); if (atomic_read(&ppc_n_lost_interrupts) != 0) do_IRQ(regs); hardirq_enter(cpu); while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0) { jiffy_stamp += tb_ticks_per_jiffy; if (!user_mode(regs)) ppc_do_profile(instruction_pointer(regs)); if (unlikely(!heartbeat_count(cpu)--) && heartbeat_reset(cpu)) { ppc_md.heartbeat(); heartbeat_count(cpu) = heartbeat_reset(cpu); } if (cpu) continue; /* We are in an interrupt, no need to save/restore flags */ write_lock(&xtime_lock); tb_last_stamp = jiffy_stamp; do_timer(regs); /* * update the rtc when needed, this should be performed on the * right fraction of a second. Half or full second ? * Full second works on mk48t59 clocks, others need testing. * Note that this update is basically only used through * the adjtimex system calls. Setting the HW clock in * any other way is a /dev/rtc and userland business. * This is still wrong by -0.5/+1.5 jiffies because of the * timer interrupt resolution and possible delay, but here we * hit a quantization limit which can only be solved by higher * resolution timers and decoupling time management from timer * interrupts. This is also wrong on the clocks * which require being written at the half second boundary. * We should have an rtc call that only sets the minutes and * seconds like on Intel to avoid problems with non UTC clocks. */ if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 && xtime.tv_sec - last_rtc_update >= 659 && abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ && jiffies - wall_jiffies == 1) { if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0) last_rtc_update = xtime.tv_sec+1; else /* Try again one minute later */ last_rtc_update += 60; } write_unlock(&xtime_lock); } if (!disarm_decr[cpu]) set_dec(next_dec); last_jiffy_stamp(cpu) = jiffy_stamp; #ifdef CONFIG_SMP smp_local_timer_interrupt(regs); #endif /* CONFIG_SMP */ hardirq_exit(cpu); if (softirq_pending(cpu)) do_softirq(); return 1; /* lets ret_from_int know we can do checks */ }