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/errno.h> 11 #include <linux/types.h> !! 14 #include <linux/export.h> 12 #include <linux/kernel.h> !! 15 #include <linux/module.h> 13 #include <linux/init.h> << 14 #include <linux/sched.h> 16 #include <linux/sched.h> >> 17 #include <linux/kernel.h> 15 #include <linux/param.h> 18 #include <linux/param.h> >> 19 #include <linux/string.h> >> 20 #include <linux/mm.h> >> 21 #include <linux/rtc.h> >> 22 #include <linux/platform_device.h> >> 23 >> 24 #include <asm/machdep.h> >> 25 #include <asm/io.h> >> 26 #include <asm/irq_regs.h> >> 27 16 #include <linux/time.h> 28 #include <linux/time.h> 17 #include <linux/timex.h> 29 #include <linux/timex.h> 18 #include <linux/smp.h> !! 30 #include <linux/profile.h> 19 #include <linux/spinlock.h> << 20 #include <linux/export.h> << 21 #include <linux/cpufreq.h> << 22 #include <linux/delay.h> << 23 31 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 32 36 static int cpufreq_callback(struct notifier_bl !! 33 unsigned long (*mach_random_get_entropy)(void); 37 unsigned long val, !! 34 EXPORT_SYMBOL_GPL(mach_random_get_entropy); 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 << 51 /* Save the initial values of the lpje << 52 if (!glb_lpj_ref) { << 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 35 81 return NOTIFY_OK; << 82 } << 83 << 84 static struct notifier_block cpufreq_notifier << 85 .notifier_call = cpufreq_callback, << 86 }; << 87 << 88 static int __init register_cpufreq_notifier(vo << 89 { << 90 return cpufreq_register_notifier(&cpuf << 91 CPUFR << 92 } << 93 core_initcall(register_cpufreq_notifier); << 94 << 95 #endif /* CONFIG_CPU_FREQ */ << 96 36 97 /* 37 /* 98 * forward reference !! 38 * timer_interrupt() needs to keep up the real-time clock, >> 39 * as well as call the "xtime_update()" routine every clocktick 99 */ 40 */ 100 DEFINE_SPINLOCK(rtc_lock); !! 41 static irqreturn_t timer_interrupt(int irq, void *dummy) 101 EXPORT_SYMBOL(rtc_lock); !! 42 { >> 43 xtime_update(1); >> 44 update_process_times(user_mode(get_irq_regs())); >> 45 profile_tick(CPU_PROFILING); >> 46 >> 47 #ifdef CONFIG_HEARTBEAT >> 48 /* use power LED as a heartbeat instead -- much more useful >> 49 for debugging -- based on the version for PReP by Cort */ >> 50 /* acts like an actual heart beat -- ie thump-thump-pause... */ >> 51 if (mach_heartbeat) { >> 52 static unsigned cnt = 0, period = 0, dist = 0; >> 53 >> 54 if (cnt == 0 || cnt == dist) >> 55 mach_heartbeat( 1 ); >> 56 else if (cnt == 7 || cnt == dist+7) >> 57 mach_heartbeat( 0 ); >> 58 >> 59 if (++cnt > period) { >> 60 cnt = 0; >> 61 /* The hyperbolic function below modifies the heartbeat period >> 62 * length in dependency of the current (5min) load. It goes >> 63 * through the points f(0)=126, f(1)=86, f(5)=51, >> 64 * f(inf)->30. */ >> 65 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; >> 66 dist = period / 4; >> 67 } >> 68 } >> 69 #endif /* CONFIG_HEARTBEAT */ >> 70 return IRQ_HANDLED; >> 71 } 102 72 103 static int null_perf_irq(void) !! 73 void read_persistent_clock(struct timespec *ts) 104 { 74 { 105 return 0; !! 75 struct rtc_time time; >> 76 ts->tv_sec = 0; >> 77 ts->tv_nsec = 0; >> 78 >> 79 if (mach_hwclk) { >> 80 mach_hwclk(0, &time); >> 81 >> 82 if ((time.tm_year += 1900) < 1970) >> 83 time.tm_year += 100; >> 84 ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, >> 85 time.tm_hour, time.tm_min, time.tm_sec); >> 86 } 106 } 87 } 107 88 108 int (*perf_irq)(void) = null_perf_irq; !! 89 #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET 109 90 110 EXPORT_SYMBOL(perf_irq); !! 91 static int __init rtc_init(void) >> 92 { >> 93 struct platform_device *pdev; 111 94 112 /* !! 95 if (!mach_hwclk) 113 * time_init() - it does the following things. !! 96 return -ENODEV; 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 97 123 unsigned int mips_hpt_frequency; !! 98 pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); 124 EXPORT_SYMBOL_GPL(mips_hpt_frequency); !! 99 return PTR_ERR_OR_ZERO(pdev); >> 100 } 125 101 126 static __init int cpu_has_mfc0_count_bug(void) !! 102 module_init(rtc_init); 127 { << 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 << 139 case CPU_R4400PC: << 140 case CPU_R4400SC: << 141 case CPU_R4400MC: << 142 /* << 143 * The published errata for th << 144 * has the mfc0 from count bug << 145 * produced. << 146 */ << 147 return 1; << 148 } << 149 103 150 return 0; !! 104 #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ 151 } << 152 105 153 void __init time_init(void) 106 void __init time_init(void) 154 { 107 { 155 plat_time_init(); !! 108 mach_sched_init(timer_interrupt); 156 << 157 /* << 158 * The use of the R4k timer as a clock << 159 * if reading the Count register might << 160 * interrupt, then we don't use the ti << 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 */ << 165 if (mips_clockevent_init() != 0 || !cp << 166 init_mips_clocksource(); << 167 } 109 } 168 110
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.