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 << 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 << 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 31 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 32 81 return NOTIFY_OK; !! 33 unsigned long (*mach_random_get_entropy)(void); 82 } !! 34 EXPORT_SYMBOL_GPL(mach_random_get_entropy); 83 35 84 static struct notifier_block cpufreq_notifier << 85 .notifier_call = cpufreq_callback, << 86 }; << 87 36 88 static int __init register_cpufreq_notifier(vo !! 37 /* >> 38 * timer_interrupt() needs to keep up the real-time clock, >> 39 * as well as call the "xtime_update()" routine every clocktick >> 40 */ >> 41 static irqreturn_t timer_interrupt(int irq, void *dummy) 89 { 42 { 90 return cpufreq_register_notifier(&cpuf !! 43 xtime_update(1); 91 CPUFR !! 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; 92 } 71 } 93 core_initcall(register_cpufreq_notifier); << 94 72 95 #endif /* CONFIG_CPU_FREQ */ !! 73 void read_persistent_clock(struct timespec *ts) >> 74 { >> 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 } >> 87 } 96 88 97 /* !! 89 #if defined(CONFIG_ARCH_USES_GETTIMEOFFSET) && IS_ENABLED(CONFIG_RTC_DRV_GENERIC) 98 * forward reference !! 90 static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm) 99 */ !! 91 { 100 DEFINE_SPINLOCK(rtc_lock); !! 92 mach_hwclk(0, tm); 101 EXPORT_SYMBOL(rtc_lock); !! 93 return rtc_valid_tm(tm); >> 94 } 102 95 103 static int null_perf_irq(void) !! 96 static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm) 104 { 97 { >> 98 if (mach_hwclk(1, tm) < 0) >> 99 return -EOPNOTSUPP; 105 return 0; 100 return 0; 106 } 101 } 107 102 108 int (*perf_irq)(void) = null_perf_irq; !! 103 static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) >> 104 { >> 105 struct rtc_pll_info pll; >> 106 struct rtc_pll_info __user *argp = (void __user *)arg; 109 107 110 EXPORT_SYMBOL(perf_irq); !! 108 switch (cmd) { >> 109 case RTC_PLL_GET: >> 110 if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll)) >> 111 return -EINVAL; >> 112 return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0; >> 113 >> 114 case RTC_PLL_SET: >> 115 if (!mach_set_rtc_pll) >> 116 return -EINVAL; >> 117 if (!capable(CAP_SYS_TIME)) >> 118 return -EACCES; >> 119 if (copy_from_user(&pll, argp, sizeof(pll))) >> 120 return -EFAULT; >> 121 return mach_set_rtc_pll(&pll); >> 122 } 111 123 112 /* !! 124 return -ENOIOCTLCMD; 113 * time_init() - it does the following things. !! 125 } 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 126 123 unsigned int mips_hpt_frequency; !! 127 static const struct rtc_class_ops generic_rtc_ops = { 124 EXPORT_SYMBOL_GPL(mips_hpt_frequency); !! 128 .ioctl = rtc_ioctl, >> 129 .read_time = rtc_generic_get_time, >> 130 .set_time = rtc_generic_set_time, >> 131 }; 125 132 126 static __init int cpu_has_mfc0_count_bug(void) !! 133 static int __init rtc_init(void) 127 { 134 { 128 switch (current_cpu_type()) { !! 135 struct platform_device *pdev; 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 136 150 return 0; !! 137 if (!mach_hwclk) >> 138 return -ENODEV; >> 139 >> 140 pdev = platform_device_register_data(NULL, "rtc-generic", -1, >> 141 &generic_rtc_ops, >> 142 sizeof(generic_rtc_ops)); >> 143 return PTR_ERR_OR_ZERO(pdev); 151 } 144 } 152 145 >> 146 module_init(rtc_init); >> 147 >> 148 #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ >> 149 153 void __init time_init(void) 150 void __init time_init(void) 154 { 151 { 155 plat_time_init(); !! 152 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 } 153 } 168 154
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.