📄 time.c
字号:
static int set_rtc_mmss(unsigned long nowtime){ int retval = 0; int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); cmos_minutes = CMOS_READ(RTC_MINUTES); if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(cmos_minutes); /* * since we're only adjusting minutes and seconds, * don't interfere with hour overflow. This avoids * messing with unknown time zones but requires your * RTC not to be off by more than 15 minutes */ real_seconds = nowtime % 60; real_minutes = nowtime / 60; if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) real_minutes += 30; /* correct for half hour time zone */ real_minutes %= 60; if (abs(real_minutes - cmos_minutes) < 30) { if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BIN_TO_BCD(real_seconds); BIN_TO_BCD(real_minutes); } 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); return retval;}/* last time the cmos clock got updated */static long last_rtc_update;/* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */static void inlinetimer_interrupt(int irq, void *dev_id, struct pt_regs * regs){#ifdef CONFIG_DDB5074 static unsigned cnt, period, dist; if (cnt == 0 || cnt == dist) ddb5074_led_d2(1); else if (cnt == 7 || cnt == dist+7) ddb5074_led_d2(0); if (++cnt > period) { cnt = 0; /* The hyperbolic function below modifies the heartbeat period * length in dependency of the current (5min) load. It goes * through the points f(0)=126, f(1)=86, f(5)=51, * f(inf)->30. */ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; dist = period / 4; }#endif if(!user_mode(regs)) { if (prof_buffer && current->pid) { extern int _stext; unsigned long pc = regs->cp0_epc; pc -= (unsigned long) &_stext; pc >>= prof_shift; /* * Dont ignore out-of-bounds pc values silently, * put them into the last histogram slot, so if * present, they will show up as a sharp peak. */ if (pc > prof_len-1) pc = prof_len-1; atomic_inc((atomic_t *)&prof_buffer[pc]); } } do_timer(regs); /* * 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. */ read_lock (&xtime_lock); 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 */ } /* As we return to user mode fire off the other CPU schedulers.. this is basically because we don't yet share IRQ's around. This message is rigged to be safe on the 386 - basically it's a hack, so don't look closely for now.. */ /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */ read_unlock (&xtime_lock); }static inline void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs){ unsigned int count; /* * The cycle counter is only 32 bit which is good for about * a minute at current count rates of upto 150MHz or so. */ count = read_32bit_cp0_register(CP0_COUNT); timerhi += (count < timerlo); /* Wrap around */ timerlo = count;#ifdef CONFIG_SGI_IP22 /* Since we don't get anything but r4k timer interrupts, we need to * set this up so that we'll get one next time. Fortunately since we * have timerhi/timerlo, we don't care so much if we miss one. So * we need only ask for the next in r4k_interval counts. On other * archs we have a real timer, so we don't want this. */ write_32bit_cp0_register (CP0_COMPARE, (unsigned long) (count + r4k_interval)); kstat.irqs[0][irq]++;#endif timer_interrupt(irq, dev_id, regs); if (!jiffies) { /* * If jiffies has overflowed in this timer_interrupt we must * update the timer[hi]/[lo] to make do_fast_gettimeoffset() * quotient calc still valid. -arca */ timerhi = timerlo = 0; }}void indy_r4k_timer_interrupt (struct pt_regs *regs){ static const int INDY_R4K_TIMER_IRQ = 7; r4k_timer_interrupt (INDY_R4K_TIMER_IRQ, NULL, regs);}char cyclecounter_available;static inline void init_cycle_counter(void){ switch(mips_cputype) { case CPU_UNKNOWN: case CPU_R2000: case CPU_R3000: case CPU_R3000A: case CPU_R3041: case CPU_R3051: case CPU_R3052: case CPU_R3081: case CPU_R3081E: case CPU_R6000: case CPU_R6000A: case CPU_R8000: /* Not shure about that one, play safe */ cyclecounter_available = 0; break; case CPU_R4000PC: case CPU_R4000SC: case CPU_R4000MC: case CPU_R4200: case CPU_R4400PC: case CPU_R4400SC: case CPU_R4400MC: case CPU_R4600: case CPU_R10000: case CPU_R4300: case CPU_R4650: case CPU_R4700: case CPU_R5000: case CPU_R5000A: case CPU_R4640: case CPU_NEVADA: cyclecounter_available = 1; break; }}struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};void (*board_time_init)(struct irqaction *irq);void __init time_init(void){ unsigned int epoch = 0, year, mon, day, hour, min, sec; int i; /* 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); } /* Attempt to guess the epoch. This is the same heuristic as in rtc.c so no stupid things will happen to timekeeping. Who knows, maybe Ultrix also uses 1952 as epoch ... */ if (year > 10 && year < 44) { epoch = 1980; } else if (year < 96) { epoch = 1952; } year += epoch; write_lock_irq (&xtime_lock); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_usec = 0; write_unlock_irq (&xtime_lock); init_cycle_counter(); if (cyclecounter_available) { write_32bit_cp0_register(CP0_COUNT, 0); do_gettimeoffset = do_fast_gettimeoffset; irq0.handler = r4k_timer_interrupt; } board_time_init(&irq0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -