1 // SPDX-License-Identifier: GPL-2.0-or-later << 2 /* 1 /* 3 * Copyright 2001 MontaVista Software Inc. !! 2 * linux/arch/m68k/kernel/time.c 4 * Author: Jun Sun, jsun@mvista.com or jsun@ju << 5 * Copyright (c) 2003, 2004 Maciej W. Rozycki << 6 * 3 * 7 * Common time service routines for MIPS machi !! 4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds >> 5 * >> 6 * This file contains the m68k-specific time handling details. >> 7 * Most of the stuff is located in the machine specific files. >> 8 * >> 9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 >> 10 * "A Kernel Model for Precision Timekeeping" by Dave Mills 8 */ 11 */ 9 #include <linux/bug.h> !! 12 10 #include <linux/clockchips.h> !! 13 #include <linux/config.h> /* CONFIG_HEARTBEAT */ 11 #include <linux/types.h> !! 14 #include <linux/errno.h> 12 #include <linux/kernel.h> << 13 #include <linux/init.h> << 14 #include <linux/sched.h> 15 #include <linux/sched.h> >> 16 #include <linux/kernel.h> 15 #include <linux/param.h> 17 #include <linux/param.h> 16 #include <linux/time.h> !! 18 #include <linux/string.h> 17 #include <linux/timex.h> !! 19 #include <linux/mm.h> 18 #include <linux/smp.h> << 19 #include <linux/spinlock.h> << 20 #include <linux/export.h> << 21 #include <linux/cpufreq.h> << 22 #include <linux/delay.h> << 23 << 24 #include <asm/cpu-features.h> << 25 #include <asm/cpu-type.h> << 26 #include <asm/div64.h> << 27 #include <asm/time.h> << 28 << 29 #ifdef CONFIG_CPU_FREQ << 30 << 31 static DEFINE_PER_CPU(unsigned long, pcp_lpj_r << 32 static DEFINE_PER_CPU(unsigned long, pcp_lpj_r << 33 static unsigned long glb_lpj_ref; << 34 static unsigned long glb_lpj_ref_freq; << 35 << 36 static int cpufreq_callback(struct notifier_bl << 37 unsigned long val, << 38 { << 39 struct cpufreq_freqs *freq = data; << 40 struct cpumask *cpus = freq->policy->c << 41 unsigned long lpj; << 42 int cpu; << 43 << 44 /* << 45 * Skip lpj numbers adjustment if the << 46 * the loops delay. (Is this possible? << 47 */ << 48 if (freq->flags & CPUFREQ_CONST_LOOPS) << 49 return NOTIFY_OK; << 50 20 51 /* Save the initial values of the lpje !! 21 #include <asm/machdep.h> 52 if (!glb_lpj_ref) { !! 22 #include <asm/io.h> 53 glb_lpj_ref = boot_cpu_data.ud << 54 glb_lpj_ref_freq = freq->old; << 55 << 56 for_each_online_cpu(cpu) { << 57 per_cpu(pcp_lpj_ref, c << 58 cpu_data[cpu]. << 59 per_cpu(pcp_lpj_ref_fr << 60 } << 61 } << 62 << 63 /* << 64 * Adjust global lpj variable and per- << 65 * accordance with the new CPU frequen << 66 */ << 67 if ((val == CPUFREQ_PRECHANGE && freq << 68 (val == CPUFREQ_POSTCHANGE && freq << 69 loops_per_jiffy = cpufreq_scal << 70 << 71 << 72 << 73 for_each_cpu(cpu, cpus) { << 74 lpj = cpufreq_scale(pe << 75 pe << 76 fr << 77 cpu_data[cpu].udelay_v << 78 } << 79 } << 80 23 81 return NOTIFY_OK; !! 24 #include <linux/timex.h> 82 } << 83 25 84 static struct notifier_block cpufreq_notifier << 85 .notifier_call = cpufreq_callback, << 86 }; << 87 26 88 static int __init register_cpufreq_notifier(vo !! 27 static inline int set_rtc_mmss(unsigned long nowtime) 89 { 28 { 90 return cpufreq_register_notifier(&cpuf !! 29 if (mach_set_clock_mmss) 91 CPUFR !! 30 return mach_set_clock_mmss (nowtime); >> 31 return -1; 92 } 32 } 93 core_initcall(register_cpufreq_notifier); << 94 33 95 #endif /* CONFIG_CPU_FREQ */ !! 34 static inline void do_profile (unsigned long pc) >> 35 { >> 36 if (prof_buffer && current->pid) { >> 37 extern int _stext; >> 38 pc -= (unsigned long) &_stext; >> 39 pc >>= prof_shift; >> 40 if (pc < prof_len) >> 41 ++prof_buffer[pc]; >> 42 else >> 43 /* >> 44 * Don't ignore out-of-bounds PC values silently, >> 45 * put them into the last histogram slot, so if >> 46 * present, they will show up as a sharp peak. >> 47 */ >> 48 ++prof_buffer[prof_len-1]; >> 49 } >> 50 } 96 51 97 /* 52 /* 98 * forward reference !! 53 * timer_interrupt() needs to keep up the real-time clock, >> 54 * as well as call the "do_timer()" routine every clocktick 99 */ 55 */ 100 DEFINE_SPINLOCK(rtc_lock); !! 56 static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) 101 EXPORT_SYMBOL(rtc_lock); << 102 << 103 static int null_perf_irq(void) << 104 { 57 { 105 return 0; !! 58 do_timer(regs); >> 59 >> 60 if (!user_mode(regs)) >> 61 do_profile(regs->pc); >> 62 >> 63 #ifdef CONFIG_HEARTBEAT >> 64 /* use power LED as a heartbeat instead -- much more useful >> 65 for debugging -- based on the version for PReP by Cort */ >> 66 /* acts like an actual heart beat -- ie thump-thump-pause... */ >> 67 if (mach_heartbeat) { >> 68 static unsigned cnt = 0, period = 0, dist = 0; >> 69 >> 70 if (cnt == 0 || cnt == dist) >> 71 mach_heartbeat( 1 ); >> 72 else if (cnt == 7 || cnt == dist+7) >> 73 mach_heartbeat( 0 ); >> 74 >> 75 if (++cnt > period) { >> 76 cnt = 0; >> 77 /* The hyperbolic function below modifies the heartbeat period >> 78 * length in dependency of the current (5min) load. It goes >> 79 * through the points f(0)=126, f(1)=86, f(5)=51, >> 80 * f(inf)->30. */ >> 81 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; >> 82 dist = period / 4; >> 83 } >> 84 } >> 85 #endif /* CONFIG_HEARTBEAT */ 106 } 86 } 107 87 108 int (*perf_irq)(void) = null_perf_irq; !! 88 void time_init(void) >> 89 { >> 90 unsigned int year, mon, day, hour, min, sec; 109 91 110 EXPORT_SYMBOL(perf_irq); !! 92 extern void arch_gettod(int *year, int *mon, int *day, int *hour, >> 93 int *min, int *sec); 111 94 112 /* !! 95 arch_gettod (&year, &mon, &day, &hour, &min, &sec); 113 * time_init() - it does the following things. << 114 * << 115 * 1) plat_time_init() - << 116 * a) (optional) set up RTC routines, << 117 * b) (optional) calibrate and set the mi << 118 * (only needed if you intended to us << 119 * source) << 120 * 2) calculate a couple of cached variables f << 121 */ << 122 96 123 unsigned int mips_hpt_frequency; !! 97 if ((year += 1900) < 1970) 124 EXPORT_SYMBOL_GPL(mips_hpt_frequency); !! 98 year += 100; >> 99 xtime.tv_sec = mktime(year, mon, day, hour, min, sec); >> 100 xtime.tv_usec = 0; 125 101 126 static __init int cpu_has_mfc0_count_bug(void) !! 102 mach_sched_init(timer_interrupt); 127 { !! 103 } 128 switch (current_cpu_type()) { << 129 case CPU_R4000PC: << 130 case CPU_R4000SC: << 131 case CPU_R4000MC: << 132 /* << 133 * V3.0 is documented as suffe << 134 * Afaik this is the last vers << 135 * were marketed as R4400. << 136 */ << 137 return 1; << 138 104 139 case CPU_R4400PC: !! 105 extern rwlock_t xtime_lock; 140 case CPU_R4400SC: !! 106 141 case CPU_R4400MC: !! 107 /* 142 /* !! 108 * This version of gettimeofday has near microsecond resolution. 143 * The published errata for th !! 109 */ 144 * has the mfc0 from count bug !! 110 void do_gettimeofday(struct timeval *tv) 145 * produced. !! 111 { 146 */ !! 112 extern unsigned long wall_jiffies; 147 return 1; !! 113 unsigned long flags; >> 114 unsigned long usec, sec, lost; >> 115 >> 116 read_lock_irqsave(&xtime_lock, flags); >> 117 usec = mach_gettimeoffset(); >> 118 lost = jiffies - wall_jiffies; >> 119 if (lost) >> 120 usec += lost * (1000000/HZ); >> 121 sec = xtime.tv_sec; >> 122 usec += xtime.tv_usec; >> 123 read_unlock_irqrestore(&xtime_lock, flags); >> 124 >> 125 while (usec >= 1000000) { >> 126 usec -= 1000000; >> 127 sec++; 148 } 128 } 149 129 150 return 0; !! 130 tv->tv_sec = sec; >> 131 tv->tv_usec = usec; 151 } 132 } 152 133 153 void __init time_init(void) !! 134 void do_settimeofday(struct timeval *tv) 154 { 135 { 155 plat_time_init(); !! 136 write_lock_irq(&xtime_lock); 156 !! 137 /* This is revolting. We need to set the xtime.tv_usec 157 /* !! 138 * correctly. However, the value in this location is 158 * The use of the R4k timer as a clock !! 139 * is value at the last tick. 159 * if reading the Count register might !! 140 * Discover what correction gettimeofday 160 * interrupt, then we don't use the ti !! 141 * would have done, and then undo it! 161 * We may still use the timer as a clo << 162 * timer interrupt isn't reliable; the << 163 * matter then, because we don't use t << 164 */ 142 */ 165 if (mips_clockevent_init() != 0 || !cp !! 143 tv->tv_usec -= mach_gettimeoffset(); 166 init_mips_clocksource(); !! 144 >> 145 while (tv->tv_usec < 0) { >> 146 tv->tv_usec += 1000000; >> 147 tv->tv_sec--; >> 148 } >> 149 >> 150 xtime = *tv; >> 151 time_adjust = 0; /* stop active adjtime() */ >> 152 time_status |= STA_UNSYNC; >> 153 time_maxerror = NTP_PHASE_LIMIT; >> 154 time_esterror = NTP_PHASE_LIMIT; >> 155 write_unlock_irq(&xtime_lock); 167 } 156 } 168 157
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.