1 // SPDX-License-Identifier: GPL-2.0-or-later !! 1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 2 /* 3 * Copyright 2001 MontaVista Software Inc. !! 3 * 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 * 4 * 7 * Common time service routines for MIPS machi !! 5 * Copyright (C) 1991, 1992, 1995 Linus Torvalds >> 6 * >> 7 * This file contains the m68k-specific time handling details. >> 8 * Most of the stuff is located in the machine specific files. >> 9 * >> 10 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 >> 11 * "A Kernel Model for Precision Timekeeping" by Dave Mills 8 */ 12 */ 9 #include <linux/bug.h> !! 13 10 #include <linux/clockchips.h> !! 14 #include <linux/errno.h> 11 #include <linux/types.h> !! 15 #include <linux/export.h> 12 #include <linux/kernel.h> !! 16 #include <linux/module.h> 13 #include <linux/init.h> << 14 #include <linux/sched.h> 17 #include <linux/sched.h> >> 18 #include <linux/sched/loadavg.h> >> 19 #include <linux/kernel.h> 15 #include <linux/param.h> 20 #include <linux/param.h> >> 21 #include <linux/string.h> >> 22 #include <linux/mm.h> >> 23 #include <linux/rtc.h> >> 24 #include <linux/platform_device.h> >> 25 >> 26 #include <asm/machdep.h> >> 27 #include <asm/io.h> >> 28 #include <asm/irq_regs.h> >> 29 16 #include <linux/time.h> 30 #include <linux/time.h> 17 #include <linux/timex.h> 31 #include <linux/timex.h> 18 #include <linux/smp.h> !! 32 #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 33 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 34 63 /* !! 35 unsigned long (*mach_random_get_entropy)(void); 64 * Adjust global lpj variable and per- !! 36 EXPORT_SYMBOL_GPL(mach_random_get_entropy); 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 37 81 return NOTIFY_OK; !! 38 #ifdef CONFIG_HEARTBEAT >> 39 void timer_heartbeat(void) >> 40 { >> 41 /* use power LED as a heartbeat instead -- much more useful >> 42 for debugging -- based on the version for PReP by Cort */ >> 43 /* acts like an actual heart beat -- ie thump-thump-pause... */ >> 44 if (mach_heartbeat) { >> 45 static unsigned cnt = 0, period = 0, dist = 0; >> 46 >> 47 if (cnt == 0 || cnt == dist) >> 48 mach_heartbeat( 1 ); >> 49 else if (cnt == 7 || cnt == dist+7) >> 50 mach_heartbeat( 0 ); >> 51 >> 52 if (++cnt > period) { >> 53 cnt = 0; >> 54 /* The hyperbolic function below modifies the heartbeat period >> 55 * length in dependency of the current (5min) load. It goes >> 56 * through the points f(0)=126, f(1)=86, f(5)=51, >> 57 * f(inf)->30. */ >> 58 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; >> 59 dist = period / 4; >> 60 } >> 61 } 82 } 62 } >> 63 #endif /* CONFIG_HEARTBEAT */ 83 64 84 static struct notifier_block cpufreq_notifier !! 65 #ifdef CONFIG_M68KCLASSIC 85 .notifier_call = cpufreq_callback, !! 66 /* machine dependent timer functions */ 86 }; !! 67 int (*mach_hwclk) (int, struct rtc_time*); >> 68 EXPORT_SYMBOL(mach_hwclk); >> 69 >> 70 int (*mach_get_rtc_pll)(struct rtc_pll_info *); >> 71 int (*mach_set_rtc_pll)(struct rtc_pll_info *); >> 72 EXPORT_SYMBOL(mach_get_rtc_pll); >> 73 EXPORT_SYMBOL(mach_set_rtc_pll); 87 74 88 static int __init register_cpufreq_notifier(vo !! 75 #if !IS_BUILTIN(CONFIG_RTC_DRV_GENERIC) >> 76 void read_persistent_clock64(struct timespec64 *ts) 89 { 77 { 90 return cpufreq_register_notifier(&cpuf !! 78 struct rtc_time time; 91 CPUFR << 92 } << 93 core_initcall(register_cpufreq_notifier); << 94 79 95 #endif /* CONFIG_CPU_FREQ */ !! 80 ts->tv_sec = 0; >> 81 ts->tv_nsec = 0; 96 82 97 /* !! 83 if (!mach_hwclk) 98 * forward reference !! 84 return; 99 */ << 100 DEFINE_SPINLOCK(rtc_lock); << 101 EXPORT_SYMBOL(rtc_lock); << 102 85 103 static int null_perf_irq(void) !! 86 mach_hwclk(0, &time); >> 87 >> 88 ts->tv_sec = mktime64(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, >> 89 time.tm_hour, time.tm_min, time.tm_sec); >> 90 } >> 91 #endif >> 92 >> 93 #if IS_ENABLED(CONFIG_RTC_DRV_GENERIC) >> 94 static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm) 104 { 95 { >> 96 mach_hwclk(0, tm); 105 return 0; 97 return 0; 106 } 98 } 107 99 108 int (*perf_irq)(void) = null_perf_irq; !! 100 static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm) >> 101 { >> 102 if (mach_hwclk(1, tm) < 0) >> 103 return -EOPNOTSUPP; >> 104 return 0; >> 105 } 109 106 110 EXPORT_SYMBOL(perf_irq); !! 107 static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) >> 108 { >> 109 struct rtc_pll_info pll; >> 110 struct rtc_pll_info __user *argp = (void __user *)arg; 111 111 112 /* !! 112 switch (cmd) { 113 * time_init() - it does the following things. !! 113 case RTC_PLL_GET: 114 * !! 114 if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll)) 115 * 1) plat_time_init() - !! 115 return -EINVAL; 116 * a) (optional) set up RTC routines, !! 116 return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0; 117 * b) (optional) calibrate and set the mi !! 117 118 * (only needed if you intended to us !! 118 case RTC_PLL_SET: 119 * source) !! 119 if (!mach_set_rtc_pll) 120 * 2) calculate a couple of cached variables f !! 120 return -EINVAL; 121 */ !! 121 if (!capable(CAP_SYS_TIME)) >> 122 return -EACCES; >> 123 if (copy_from_user(&pll, argp, sizeof(pll))) >> 124 return -EFAULT; >> 125 return mach_set_rtc_pll(&pll); >> 126 } 122 127 123 unsigned int mips_hpt_frequency; !! 128 return -ENOIOCTLCMD; 124 EXPORT_SYMBOL_GPL(mips_hpt_frequency); !! 129 } >> 130 >> 131 static const struct rtc_class_ops generic_rtc_ops = { >> 132 .ioctl = rtc_ioctl, >> 133 .read_time = rtc_generic_get_time, >> 134 .set_time = rtc_generic_set_time, >> 135 }; 125 136 126 static __init int cpu_has_mfc0_count_bug(void) !! 137 static int __init rtc_init(void) 127 { 138 { 128 switch (current_cpu_type()) { !! 139 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 140 150 return 0; !! 141 if (!mach_hwclk) >> 142 return -ENODEV; >> 143 >> 144 pdev = platform_device_register_data(NULL, "rtc-generic", -1, >> 145 &generic_rtc_ops, >> 146 sizeof(generic_rtc_ops)); >> 147 return PTR_ERR_OR_ZERO(pdev); 151 } 148 } 152 149 >> 150 module_init(rtc_init); >> 151 #endif /* CONFIG_RTC_DRV_GENERIC */ >> 152 #endif /* CONFIG M68KCLASSIC */ >> 153 153 void __init time_init(void) 154 void __init time_init(void) 154 { 155 { 155 plat_time_init(); !! 156 mach_sched_init(); 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 } 157 } 168 158
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.