linux/arch/i386/kernel/time.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/i386/kernel/time.c
   3 *
   4 *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
   5 *
   6 * This file contains the PC-specific time handling details:
   7 * reading the RTC at bootup, etc..
   8 * 1994-07-02    Alan Modra
   9 *      fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
  10 * 1995-03-26    Markus Kuhn
  11 *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
  12 *      precision CMOS clock update
  13 * 1996-05-03    Ingo Molnar
  14 *      fixed time warps in do_[slow|fast]_gettimeoffset()
  15 * 1997-09-10   Updated NTP code according to technical memorandum Jan '96
  16 *              "A Kernel Model for Precision Timekeeping" by Dave Mills
  17 * 1998-09-05    (Various)
  18 *      More robust do_fast_gettimeoffset() algorithm implemented
  19 *      (works with APM, Cyrix 6x86MX and Centaur C6),
  20 *      monotonic gettimeofday() with fast_get_timeoffset(),
  21 *      drift-proof precision TSC calibration on boot
  22 *      (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
  23 *      Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
  24 *      ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
  25 * 1998-12-16    Andrea Arcangeli
  26 *      Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
  27 *      because was not accounting lost_ticks.
  28 * 1998-12-24 Copyright (C) 1998  Andrea Arcangeli
  29 *      Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
  30 *      serialize accesses to xtime/lost_ticks).
  31 */
  32
  33#include <linux/errno.h>
  34#include <linux/sched.h>
  35#include <linux/kernel.h>
  36#include <linux/param.h>
  37#include <linux/string.h>
  38#include <linux/mm.h>
  39#include <linux/interrupt.h>
  40#include <linux/time.h>
  41#include <linux/delay.h>
  42#include <linux/init.h>
  43#include <linux/smp.h>
  44#include <linux/module.h>
  45#include <linux/sysdev.h>
  46#include <linux/bcd.h>
  47#include <linux/efi.h>
  48#include <linux/mca.h>
  49
  50#include <asm/io.h>
  51#include <asm/smp.h>
  52#include <asm/irq.h>
  53#include <asm/msr.h>
  54#include <asm/delay.h>
  55#include <asm/mpspec.h>
  56#include <asm/uaccess.h>
  57#include <asm/processor.h>
  58#include <asm/timer.h>
  59#include <asm/time.h>
  60
  61#include "mach_time.h"
  62
  63#include <linux/timex.h>
  64
  65#include <asm/hpet.h>
  66
  67#include <asm/arch_hooks.h>
  68
  69#include "io_ports.h"
  70
  71#include <asm/i8259.h>
  72
  73#include "do_timer.h"
  74
  75unsigned int cpu_khz;   /* Detected as we calibrate the TSC */
  76EXPORT_SYMBOL(cpu_khz);
  77
  78DEFINE_SPINLOCK(rtc_lock);
  79EXPORT_SYMBOL(rtc_lock);
  80
  81/*
  82 * This is a special lock that is owned by the CPU and holds the index
  83 * register we are working with.  It is required for NMI access to the
  84 * CMOS/RTC registers.  See include/asm-i386/mc146818rtc.h for details.
  85 */
  86volatile unsigned long cmos_lock = 0;
  87EXPORT_SYMBOL(cmos_lock);
  88
  89/* Routines for accessing the CMOS RAM/RTC. */
  90unsigned char rtc_cmos_read(unsigned char addr)
  91{
  92        unsigned char val;
  93        lock_cmos_prefix(addr);
  94        outb_p(addr, RTC_PORT(0));
  95        val = inb_p(RTC_PORT(1));
  96        lock_cmos_suffix(addr);
  97        return val;
  98}
  99EXPORT_SYMBOL(rtc_cmos_read);
 100
 101void rtc_cmos_write(unsigned char val, unsigned char addr)
 102{
 103        lock_cmos_prefix(addr);
 104        outb_p(addr, RTC_PORT(0));
 105        outb_p(val, RTC_PORT(1));
 106        lock_cmos_suffix(addr);
 107}
 108EXPORT_SYMBOL(rtc_cmos_write);
 109
 110static int set_rtc_mmss(unsigned long nowtime)
 111{
 112        int retval;
 113        unsigned long flags;
 114
 115        /* gets recalled with irq locally disabled */
 116        /* XXX - does irqsave resolve this? -johnstul */
 117        spin_lock_irqsave(&rtc_lock, flags);
 118        retval = set_wallclock(nowtime);
 119        spin_unlock_irqrestore(&rtc_lock, flags);
 120
 121        return retval;
 122}
 123
 124
 125int timer_ack;
 126
 127unsigned long profile_pc(struct pt_regs *regs)
 128{
 129        unsigned long pc = instruction_pointer(regs);
 130
 131#ifdef CONFIG_SMP
 132        if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->xcs) &&
 133            in_lock_functions(pc)) {
 134#ifdef CONFIG_FRAME_POINTER
 135                return *(unsigned long *)(regs->ebp + 4);
 136#else
 137                unsigned long *sp = (unsigned long *)&regs->esp;
 138
 139                /* Return address is either directly at stack pointer
 140                   or above a saved eflags. Eflags has bits 22-31 zero,
 141                   kernel addresses don't. */
 142                if (sp[0] >> 22)
 143                        return sp[0];
 144                if (sp[1] >> 22)
 145                        return sp[1];
 146#endif
 147        }
 148#endif
 149        return pc;
 150}
 151EXPORT_SYMBOL(profile_pc);
 152
 153/*
 154 * This is the same as the above, except we _also_ save the current
 155 * Time Stamp Counter value at the time of the timer interrupt, so that
 156 * we later on can estimate the time of day more exactly.
 157 */
 158irqreturn_t timer_interrupt(int irq, void *dev_id)
 159{
 160#ifdef CONFIG_X86_IO_APIC
 161        if (timer_ack) {
 162                /*
 163                 * Subtle, when I/O APICs are used we have to ack timer IRQ
 164                 * manually to reset the IRR bit for do_slow_gettimeoffset().
 165                 * This will also deassert NMI lines for the watchdog if run
 166                 * on an 82489DX-based system.
 167                 */
 168                spin_lock(&i8259A_lock);
 169                outb(0x0c, PIC_MASTER_OCW3);
 170                /* Ack the IRQ; AEOI will end it automatically. */
 171                inb(PIC_MASTER_POLL);
 172                spin_unlock(&i8259A_lock);
 173        }
 174#endif
 175
 176        do_timer_interrupt_hook();
 177
 178        if (MCA_bus) {
 179                /* The PS/2 uses level-triggered interrupts.  You can't
 180                turn them off, nor would you want to (any attempt to
 181                enable edge-triggered interrupts usually gets intercepted by a
 182                special hardware circuit).  Hence we have to acknowledge
 183                the timer interrupt.  Through some incredibly stupid
 184                design idea, the reset for IRQ 0 is done by setting the
 185                high bit of the PPI port B (0x61).  Note that some PS/2s,
 186                notably the 55SX, work fine if this is removed.  */
 187
 188                u8 irq_v = inb_p( 0x61 );       /* read the current state */
 189                outb_p( irq_v|0x80, 0x61 );     /* reset the IRQ */
 190        }
 191
 192        return IRQ_HANDLED;
 193}
 194
 195/* not static: needed by APM */
 196unsigned long read_persistent_clock(void)
 197{
 198        unsigned long retval;
 199        unsigned long flags;
 200
 201        spin_lock_irqsave(&rtc_lock, flags);
 202
 203        retval = get_wallclock();
 204
 205        spin_unlock_irqrestore(&rtc_lock, flags);
 206
 207        return retval;
 208}
 209
 210static void sync_cmos_clock(unsigned long dummy);
 211
 212static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
 213int no_sync_cmos_clock;
 214
 215static void sync_cmos_clock(unsigned long dummy)
 216{
 217        struct timeval now, next;
 218        int fail = 1;
 219
 220        /*
 221         * If we have an externally synchronized Linux clock, then update
 222         * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
 223         * called as close as possible to 500 ms before the new second starts.
 224         * This code is run on a timer.  If the clock is set, that timer
 225         * may not expire at the correct time.  Thus, we adjust...
 226         */
 227        if (!ntp_synced())
 228                /*
 229                 * Not synced, exit, do not restart a timer (if one is
 230                 * running, let it run out).
 231                 */
 232                return;
 233
 234        do_gettimeofday(&now);
 235        if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
 236            now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
 237                fail = set_rtc_mmss(now.tv_sec);
 238
 239        next.tv_usec = USEC_AFTER - now.tv_usec;
 240        if (next.tv_usec <= 0)
 241                next.tv_usec += USEC_PER_SEC;
 242
 243        if (!fail)
 244                next.tv_sec = 659;
 245        else
 246                next.tv_sec = 0;
 247
 248        if (next.tv_usec >= USEC_PER_SEC) {
 249                next.tv_sec++;
 250                next.tv_usec -= USEC_PER_SEC;
 251        }
 252        mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
 253}
 254
 255void notify_arch_cmos_timer(void)
 256{
 257        if (!no_sync_cmos_clock)
 258                mod_timer(&sync_cmos_timer, jiffies + 1);
 259}
 260
 261extern void (*late_time_init)(void);
 262/* Duplicate of time_init() below, with hpet_enable part added */
 263void __init hpet_time_init(void)
 264{
 265        if (!hpet_enable())
 266                setup_pit_timer();
 267        time_init_hook();
 268}
 269
 270/*
 271 * This is called directly from init code; we must delay timer setup in the
 272 * HPET case as we can't make the decision to turn on HPET this early in the
 273 * boot process.
 274 *
 275 * The chosen time_init function will usually be hpet_time_init, above, but
 276 * in the case of virtual hardware, an alternative function may be substituted.
 277 */
 278void __init time_init(void)
 279{
 280        tsc_init();
 281        late_time_init = choose_time_init();
 282}
 283
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.