📄 time.c
字号:
} CMOS_WRITE(real_seconds,RTC_SECONDS); CMOS_WRITE(real_minutes,RTC_MINUTES); } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", cmos_minutes, real_minutes); retval = -1; } /* The following flags have to be released exactly in this order, * otherwise the DS12887 (popular MC146818A clone with integrated * battery and quartz) will not reset the oscillator and will not * update precisely 500 ms later. You won't find this mentioned in * the Dallas Semiconductor data sheets, but who believes data * sheets anyway ... -- Markus Kuhn */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); spin_unlock(&rtc_lock); return retval;}/* last time the cmos clock got updated */static long last_rtc_update;int timer_ack;/* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs){#ifdef CONFIG_X86_IO_APIC if (timer_ack) { /* * Subtle, when I/O APICs are used we have to ack timer IRQ * manually to reset the IRR bit for do_slow_gettimeoffset(). * This will also deassert NMI lines for the watchdog if run * on an 82489DX-based system. */ spin_lock(&i8259A_lock); outb(0x0c, 0x20); /* Ack the IRQ; AEOI will end it automatically. */ inb(0x20); spin_unlock(&i8259A_lock); }#endif#ifdef CONFIG_VISWS /* Clear the interrupt */ co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);#endif do_timer(regs);/* * In the SMP case we use the local APIC timer interrupt to do the * profiling, except when we simulate SMP mode on a uniprocessor * system, in that case we have to call the local interrupt handler. */#ifndef CONFIG_X86_LOCAL_APIC if (!user_mode(regs)) x86_do_profile(regs->eip);#else if (!using_apic_timer) smp_local_timer_interrupt(regs);#endif /* * 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 ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660 && xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } #ifdef CONFIG_MCA if( MCA_bus ) { /* The PS/2 uses level-triggered interrupts. You can't turn them off, nor would you want to (any attempt to enable edge-triggered interrupts usually gets intercepted by a special hardware circuit). Hence we have to acknowledge the timer interrupt. Through some incredibly stupid design idea, the reset for IRQ 0 is done by setting the high bit of the PPI port B (0x61). Note that some PS/2s, notably the 55SX, work fine if this is removed. */ irq = inb_p( 0x61 ); /* read the current state */ outb_p( irq|0x80, 0x61 ); /* reset the IRQ */ }#endif}static int use_tsc;/* * This is the same as the above, except we _also_ save the current * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs){ int count; /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other * CPU. We need to avoid to SMP race with it. NOTE: we don' t need * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ write_lock(&xtime_lock); if (use_tsc) { /* * It is important that these two operations happen almost at * the same time. We do the RDTSC stuff first, since it's * faster. To avoid any inconsistencies, we need interrupts * disabled locally. */ /* * Interrupts are just disabled locally since the timer irq * has the SA_INTERRUPT flag set. -arca */ /* read Pentium cycle counter */ rdtscl(last_tsc_low); spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; spin_unlock(&i8253_lock); count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; } do_timer_interrupt(irq, NULL, regs); write_unlock(&xtime_lock);}/* not static: needed by APM */unsigned long get_cmos_time(void){ unsigned int year, mon, day, hour, min, sec; int i; spin_lock(&rtc_lock); /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ /* read RTC exactly on falling edge of update flag */ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) break; for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) break; do { /* Isn't this overkill ? UIP above should guarantee consistency */ sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); day = CMOS_READ(RTC_DAY_OF_MONTH); mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); } while (sec != CMOS_READ(RTC_SECONDS)); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); BCD_TO_BIN(day); BCD_TO_BIN(mon); BCD_TO_BIN(year); } spin_unlock(&rtc_lock); if ((year += 1900) < 1970) year += 100; return mktime(year, mon, day, hour, min, sec);}static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};/* ------ Calibrate the TSC ------- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). * Too much 64-bit arithmetic here to do this cleanly in C, and for * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) * output busy loop as low as possible. We avoid reading the CTC registers * directly because of the awkward 8-bit access mechanism of the 82C54 * device. */#define CALIBRATE_LATCH (5 * LATCH)#define CALIBRATE_TIME (5 * 1000020/HZ)static unsigned long __init calibrate_tsc(void){ /* 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 */ { unsigned long startlow, starthigh; unsigned long endlow, endhigh; unsigned long count; rdtsc(startlow,starthigh); count = 0; do { count++; } while ((inb(0x61) & 0x20) == 0); rdtsc(endlow,endhigh); last_tsc_low = endlow; /* Error: ECTCNEVERSET */ if (count <= 1) goto bad_ctc; /* 64-bit subtract - gcc just messes up with long longs */ __asm__("subl %2,%0\n\t" "sbbl %3,%1" :"=a" (endlow), "=d" (endhigh) :"g" (startlow), "g" (starthigh), "0" (endlow), "1" (endhigh)); /* Error: ECPUTOOFAST */ if (endhigh) goto bad_ctc; /* Error: ECPUTOOSLOW */ if (endlow <= CALIBRATE_TIME) goto bad_ctc; __asm__("divl %2" :"=a" (endlow), "=d" (endhigh) :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME)); return endlow; } /* * The CTC wasn't reliable: we got a hit on the very first read, * or the CPU was so fast/slow that the quotient wouldn't fit in * 32 bits.. */bad_ctc: return 0;}void __init time_init(void){ extern int x86_udelay_tsc; xtime.tv_sec = get_cmos_time(); xtime.tv_usec = 0;/* * If we have APM enabled or the CPU clock speed is variable * (CPU stops clock on HLT or slows clock to save power) * then the TSC timestamps may diverge by up to 1 jiffy from * 'real time' but nothing will break. * The most frequent case is that the CPU is "woken" from a halt * state by the timer interrupt itself, so we get 0 error. In the * rare cases where a driver would "wake" the CPU and request a * timestamp, the maximum error is < 1 jiffy. But timestamps are * still perfectly ordered. * Note that the TSC counter will be reset if APM suspends * to disk; this won't break the kernel, though, 'cuz we're * smart. See arch/i386/kernel/apm.c. */ /* * Firstly we have to do a CPU check for chips with * a potentially buggy TSC. At this point we haven't run * the ident/bugs checks so we must run this hook as it * may turn off the TSC flag. * * NOTE: this doesnt yet handle SMP 486 machines where only * some CPU's have a TSC. Thats never worked and nobody has * moaned if you have the only one in the world - you fix it! */ dodgy_tsc(); if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); if (tsc_quotient) { fast_gettimeoffset_quotient = tsc_quotient; use_tsc = 1; /* * We could be more selective here I suspect * and just enable this for the next intel chips ? */ x86_udelay_tsc = 1;#ifndef do_gettimeoffset do_gettimeoffset = do_fast_gettimeoffset;#endif /* report CPU clock rate in Hz. * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = * clock/second. Our precision is about 100 ppm. */ { unsigned long eax=0, edx=1000; __asm__("divl %2" :"=a" (cpu_khz), "=d" (edx) :"r" (tsc_quotient), "0" (eax), "1" (edx)); printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } } }#ifdef CONFIG_VISWS printk("Starting Cobalt Timer system clock\n"); /* Set the countdown value */ co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); /* Start the timer */ co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); /* Enable (unmask) the timer interrupt */ co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ setup_irq(CO_IRQ_TIMER, &irq0);#else setup_irq(0, &irq0);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -