📄 time.c
字号:
/* * linux/arch/alpha/kernel/time.c * * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds * * This file contains the PC-specific time handling details: * reading the RTC at bootup, etc.. * 1994-07-02 Alan Modra * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime * 1995-03-26 Markus Kuhn * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 * precision CMOS clock update * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills * 1997-01-09 Adrian Sun * use interval timer if CONFIG_RTC=y * 1997-10-29 John Bowman (bowman@math.ualberta.ca) * fixed tick loss calculation in timer_interrupt * (round system clock to nearest tick instead of truncating) * fixed algorithm in time_init for getting time from CMOS clock * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) * fixed algorithm in do_gettimeofday() for calculating the precise time * from processor cycle counter (now taking lost_ticks into account) * 2000-08-13 Jan-Benedict Glaw <jbglaw@lug-owl.de> * Fixed time_init to be aware of epoches != 1900. This prevents * booting up in 2048 for me;) Code is stolen from rtc.c. * 2003-06-03 R. Scott Bailey <scott.bailey@eds.com> * Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM */#include <linux/config.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/param.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/bcd.h>#include <linux/profile.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/hwrpb.h>#include <asm/8253pit.h>#include <linux/mc146818rtc.h>#include <linux/time.h>#include <linux/timex.h>#include "proto.h"#include "irq_impl.h"extern unsigned long wall_jiffies; /* kernel/timer.c */static int set_rtc_mmss(unsigned long);DEFINE_SPINLOCK(rtc_lock);#define TICK_SIZE (tick_nsec / 1000)/* * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting * by 48 gives us 16 bits for HZ while keeping the accuracy good even * for large CPU clock rates. */#define FIX_SHIFT 48/* lump static variables together for more efficient access: */static struct { /* cycle counter last time it got invoked */ __u32 last_time; /* ticks/cycle * 2^48 */ unsigned long scaled_ticks_per_cycle; /* last time the CMOS clock got updated */ time_t last_rtc_update; /* partial unused tick */ unsigned long partial_tick;} state;unsigned long est_cycle_freq;static inline __u32 rpcc(void){ __u32 result; asm volatile ("rpcc %0" : "=r"(result)); return result;}/* * Scheduler clock - returns current time in nanosec units. * * Copied from ARM code for expediency... ;-} */unsigned long long sched_clock(void){ return (unsigned long long)jiffies * (1000000000 / HZ);}/* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs){ unsigned long delta; __u32 now; long nticks;#ifndef CONFIG_SMP /* Not SMP, do kernel PC profiling here. */ profile_tick(CPU_PROFILING, regs);#endif write_seqlock(&xtime_lock); /* * Calculate how many ticks have passed since the last update, * including any previous partial leftover. Save any resulting * fraction for the next pass. */ now = rpcc(); delta = now - state.last_time; state.last_time = now; delta = delta * state.scaled_ticks_per_cycle + state.partial_tick; state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); nticks = delta >> FIX_SHIFT; while (nticks > 0) { do_timer(regs);#ifndef CONFIG_SMP update_process_times(user_mode(regs));#endif nticks--; } /* * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ if (ntp_synced() && xtime.tv_sec > state.last_rtc_update + 660 && xtime.tv_nsec >= 500000 - ((unsigned) TICK_SIZE) / 2 && xtime.tv_nsec <= 500000 + ((unsigned) TICK_SIZE) / 2) { int tmp = set_rtc_mmss(xtime.tv_sec); state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0); } write_sequnlock(&xtime_lock); return IRQ_HANDLED;}voidcommon_init_rtc(void){ unsigned char x; /* Reset periodic interrupt frequency. */ x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; /* Test includes known working values on various platforms where 0x26 is wrong; we refuse to change those. */ if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) { printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x); CMOS_WRITE(0x26, RTC_FREQ_SELECT); } /* Turn on periodic interrupts. */ x = CMOS_READ(RTC_CONTROL); if (!(x & RTC_PIE)) { printk("Turning on RTC interrupts.\n"); x |= RTC_PIE; x &= ~(RTC_AIE | RTC_UIE); CMOS_WRITE(x, RTC_CONTROL); } (void) CMOS_READ(RTC_INTR_FLAGS); outb(0x36, 0x43); /* pit counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); outb(0xb6, 0x43); /* pit counter 2: speaker */ outb(0x31, 0x42); outb(0x13, 0x42); init_rtc_irq();}/* Validate a computed cycle counter result against the known bounds for the given processor core. There's too much brokenness in the way of timing hardware for any one method to work everywhere. :-( Return 0 if the result cannot be trusted, otherwise return the argument. */static unsigned long __initvalidate_cc_value(unsigned long cc){ static struct bounds { unsigned int min, max; } cpu_hz[] __initdata = { [EV3_CPU] = { 50000000, 200000000 }, /* guess */ [EV4_CPU] = { 100000000, 300000000 }, [LCA4_CPU] = { 100000000, 300000000 }, /* guess */ [EV45_CPU] = { 200000000, 300000000 }, [EV5_CPU] = { 250000000, 433000000 }, [EV56_CPU] = { 333000000, 667000000 }, [PCA56_CPU] = { 400000000, 600000000 }, /* guess */ [PCA57_CPU] = { 500000000, 600000000 }, /* guess */ [EV6_CPU] = { 466000000, 600000000 }, [EV67_CPU] = { 600000000, 750000000 }, [EV68AL_CPU] = { 750000000, 940000000 }, [EV68CB_CPU] = { 1000000000, 1333333333 }, /* None of the following are shipping as of 2001-11-01. */ [EV68CX_CPU] = { 1000000000, 1700000000 }, /* guess */ [EV69_CPU] = { 1000000000, 1700000000 }, /* guess */ [EV7_CPU] = { 800000000, 1400000000 }, /* guess */ [EV79_CPU] = { 1000000000, 2000000000 }, /* guess */ }; /* Allow for some drift in the crystal. 10MHz is more than enough. */ const unsigned int deviation = 10000000; struct percpu_struct *cpu; unsigned int index; cpu = (struct percpu_struct *)((char*)hwrpb + hwrpb->processor_offset); index = cpu->type & 0xffffffff; /* If index out of bounds, no way to validate. */ if (index >= sizeof(cpu_hz)/sizeof(cpu_hz[0])) return cc; /* If index contains no data, no way to validate. */ if (cpu_hz[index].max == 0) return cc; if (cc < cpu_hz[index].min - deviation || cc > cpu_hz[index].max + deviation) return 0; return cc;}/* * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from * arch/i386/time.c. */#define CALIBRATE_LATCH 0xffff#define TIMEOUT_COUNT 0x100000static unsigned long __initcalibrate_cc_with_pit(void){ int cc, count = 0; /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); /* * Now let's take care of CTC channel 2 * * Set the Gate high, program CTC channel 2 for mode 0, * (interrupt on terminal count mode), binary count, * load 5 * LATCH count, (LSB and MSB) to begin countdown. */ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ cc = rpcc(); do { count++; } while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT); cc = rpcc() - cc; /* Error: ECTCNEVERSET or ECPUTOOFAST. */ if (count <= 1 || count == TIMEOUT_COUNT) return 0; return ((long)cc * PIT_TICK_RATE) / (CALIBRATE_LATCH + 1);}/* The Linux interpretation of the CMOS clock register contents: When the Update-In-Progress (UIP) flag goes from 1 to 0, the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -